後臺管理框架搭建

搭建一套通用的後臺管理框架對於以後的快速開發時是非常重要的。通常框架需要包含權限驗證、日誌、及一些基礎數據的增刪改查功能。

本框架採用Spring MVC+Mybatis+Freemarker+Adminlte前端 組合在一起搭建一個管理系統。

大概的樣子如下:
這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

1.權限

角色->應用->模塊->功能
這裏寫圖片描述

數據庫專門建立了一張功能表sys_Function,它屬於某個模塊,它有個權限值字段(該值爲2的指數倍,爲什麼,下面再解釋?)。
這裏寫圖片描述

如何判斷某個角色是否可以進行某個功能操作(例如刪除模塊)?
如上圖角色權限表sys_RolePermission所示,該表有個字段P_Value等於P_ModuleCode模塊所選功能的權限值之和。
例如功能管理模塊定義了4個功能,分別爲查看、添加、修改、刪除功能,這4個功能的權限值分別爲1、2、4、8,那麼sys_RolePermission的該模塊的權限值P_Value如果等於1,則表示只有查看功能,如果等於3,則表示具有查看和添加功能,如果要具有所有功能,則值要等於1+2+4+8=15。

那如果某個用戶多個角色對同一個模塊有不同的權限值,例如用戶x具有角色1和角色2,角色1對模塊a的權限值爲3,角色2對模塊a的權限值爲9,那用戶對模塊a的權限應該是多少呢?其實只要做一個按位與操作即可,即1&9=11,並不是1+9=10.這就是爲什麼讓功能值設置爲2的指數倍形式的原因,其實質是爲了進行二進制的操作。假如有4個功能,則將權限值用4位的二進制形式表示,每一位分別表示一個功能,0表示無權限,1表示有權限。同理3的二進制形式爲0011,9的二進制形式爲1001,作與運算後的結果爲1011,即權限值爲11。
最後判斷是否具有某功能,則用該功能權限值與計算後的角色權限值作與運算,例如上面判斷是否具有修改功能(權限值爲4),將4與11作與運算,4&11=0,則表示無權限,而添加功能(權限值2),2&11=2,則表示有權限,同理刪除功能(權限值8),8&11=8表示有權限。

2.日誌

寫日誌功能用到的是AOP切面技術,這樣可以與實際的業務代碼相分離,互不影響。

<beans:bean id="aspectEventLog" class="com.jykj.check.filter.EventLogAspect" />
    <!-- <aop:aspectj-autoproxy />  -->
    <!-- 對帶有@Operation註解的service包及其子包所有方法執行寫日誌操作   && execution(* com.jykj.check.service.*.*(..)) --> 
    <aop:config proxy-target-class="true">  
        <aop:aspect  ref="aspectEventLog">  
            <aop:pointcut id="myService"  
                expression="@annotation(com.jykj.check.annotation.Operation) and execution(* com.jykj.check.service..*.*(..)) " />  
            <aop:after-returning pointcut-ref="myService" method="doAfterReturning"/>  
            <aop:after-throwing pointcut-ref="myService" method="doAfterThrowing" throwing="ex"/>
        </aop:aspect>  
    </aop:config>
EventLogAspect.java
package com.jykj.check.filter;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.fastjson.JSON;
import com.jykj.check.annotation.Operation;
import com.jykj.check.exception.AuthorizationException;
import com.jykj.check.service.SysEventService;

//事件日誌 切面,凡是帶有 @Operation 註解的service方法都將會寫日誌
public class EventLogAspect {
    @Autowired
    SysEventService sysEventService;

    public void doAfterReturning(JoinPoint jp) throws AuthorizationException {
        Method soruceMethod = getSourceMethod(jp);
        if(soruceMethod!=null){
            Operation oper = soruceMethod.getAnnotation(Operation.class);
            if (oper != null) {
                sysEventService.insertEventLog(oper.type(),oper.desc()+"("+extractParam(jp.getArgs(),oper.arguDesc())+") 成功");
                System.out.println("切面日誌:"+oper.desc()+"("+extractParam(jp.getArgs(),oper.arguDesc())+") 成功");
            }
        }
    }
    public void doAfterThrowing(JoinPoint jp, Throwable ex) throws AuthorizationException {
        Method soruceMethod = getSourceMethod(jp);
        if(soruceMethod!=null){
            Operation oper = soruceMethod.getAnnotation(Operation.class);
            if (oper != null) {
                sysEventService.insertEventLog(oper.type(),oper.desc()+
                        "("+extractParam(jp.getArgs(),oper.arguDesc())+" 出現異常:"+ex.getMessage());
            }
        }
    }
    private Method getSourceMethod(JoinPoint jp){
        Method proxyMethod = ((MethodSignature) jp.getSignature()).getMethod();
        try {
            return jp.getTarget().getClass().getMethod(proxyMethod.getName(), proxyMethod.getParameterTypes());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }
    private String extractParam(Object[] objParam, String[] arguDesc) {
        StringBuilder sb = new StringBuilder();
        int len = objParam.length<arguDesc.length?objParam.length:arguDesc.length;//取最小值
        for (int i = 0; i < len; i++) {
            //空字符串將不解析,8個原生數據類型以及字符串直接輸出,對象用json輸出
            if(arguDesc[i]!=null && !arguDesc[i].trim().isEmpty()){
                Object obj = objParam[i];
                if(obj instanceof String)
                    sb.append(arguDesc[i]+":"+objParam[i]+",");
                else if(obj instanceof Integer || obj instanceof Byte || obj instanceof Short || obj instanceof Character
                        || obj instanceof Long || obj instanceof Double || obj instanceof Float || obj instanceof Boolean){
                    sb.append(arguDesc[i]+":"+objParam[i]+",");
                }
                else{
                    sb.append(arguDesc[i]+":"+JSON.toJSONString(obj)+",");
                }
            }
        }
        String rs = sb.toString(); 
        rs = rs.substring(0,rs.length()-1);
        return rs.length()<=400?rs:rs.substring(0,400);
    }
}

再需要寫日誌的方法(通常是service方法)上加一個自定義的註解@Operation即可

package com.jykj.check.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Descrption該註解描述方法的操作類型和方法的參數意義
 */
@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
public @interface Operation {
    /**
     * @Description描述操作類型   爲必填項,1:登錄日誌2:操作日誌
     */
    int type();

    /**
     * @Description描述操作意義   比如申報通過或者不通過等
     */
    String desc() default ""; 

    /**
     * @Description描述操作方法的參數意義 數組長度需與參數長度一致,否則會參數與描述不一致的情況
     */
    String[] arguDesc() default {};
}

3.前端框架

前端框架使用的是AdminLTE,其包含了很多技術例如bootstrap、datatables等等,非常繁雜。
可以從官網下載該框架:AdminLTE官網

4.其他

框架涉及到的東西實在是太多太多,這裏就不一 一列舉了。
開發環境:
Spring tool suite 3.9+JDK8+Sqlserver2008
Import項目後如果發現一大堆錯誤,通常是pom.xml文件中所依賴的jar包未下載,需要手動或在線下載jar包到你本地的mven倉庫中。
下面附上框架項目的下載地址,裏面包含項目以及Sqlserver的數據庫Check的備份包。

框架項目下載地址:框架項目下載

《道德經》第三章:
不上賢,使民不爭;不貴難得之貨,使民不爲盜;不見可欲,使民不亂。是以聖人之治也,虛其心,實其腹,弱其志,強其骨,恆使民無知、無慾也。使夫知不敢、弗爲而已,則無不治矣。

譯文:不推崇有才德的人,導使老百姓不互相爭奪;不珍愛難得的財物,導使老百姓不去偷竊;不顯耀足以引起貪心的事物,導使民心不被迷亂。因此,聖人的治理原則是:排空百姓的心機,填飽百姓的肚腹,減弱百姓的競爭意圖,增強百姓的筋骨體魄,經常使老百姓沒有智巧,沒有慾望。致使那些有才智的人也不敢妄爲造事。聖人按照“無爲”的原則去做,辦事順應自然,那麼,天才就不會不太平了。

無爲並非啥事都不做,無爲是執政者不爲自己去攫取民衆的利益。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章