1. 程式人生 > 其它 >SpringAop之靜態代理AspectJ

SpringAop之靜態代理AspectJ

技術標籤:技術架構後端技術springjavaaop

最近一段時間,用到了SpringAop 裡的AspectJ 靜態代理面向切面程式設計,感覺開發效率提升不少,今天特意總結一下,防止以後遺忘。
首先,總體複習一下Aop的相關知識
  1. 總體結構圖
    在這裡插入圖片描述

  2. Aop 應用場景
    Authentication 許可權、Caching 快取、Context passing 內容傳遞、Error handling 錯誤處理、Lazy loading 懶載入、Debugging 除錯、logging,tracing,profiling and monitoring 記錄跟蹤 優化 校準、Performance optimization 效能優化、Persistence 持久化、Persistence 持久化、Resource pooling 資源池、Synchronization 同步、Transactions 事務、Logging 日誌

  3. 專案例項
    例項簡介:
    通過AspectJ 在SpingBoot2+mybatis3+vue3 框架下 通過註解,切入到serviceImpl 方法級別上,動態新增引數實現sql的動態注入。
    專案背景
    省級下邊不同的市級使用者登陸後,根據該使用者屬於不同 市代號(AreaCode)來實現只能檢視屬於該區域的資料。體現在Mybatis裡的xml 動態注入sql
    配置步驟:
    (1)配置AreaScopeAOP

package com.dechnic.omsdc.server.admin.aop;

import com.dechnic.omsdc.server.admin.config.Config;
import com.dechnic.omsdc.server.admin.entity.BaseEntity; import com.dechnic.omsdc.server.admin.entity.TSysPerm; import com.dechnic.omsdc.server.admin.entity.TSysRole; import com.dechnic.omsdc.server.admin.entity.TSysUser; import com.dechnic.omsdc.server.admin.service.TSysRoleService; import com.dechnic.
omsdc.server.common.annotation.AreaScope; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.lang.reflect.Method; import java.util.List; import java.util.Map; @Slf4j @Component @Aspect public class AreaScopeAOP { public static final String AREA = "area"; // 區域 public static final String AREA_ForReport = "areaForReport"; // 查詢報表用 public static final String AREA_SCOPE = "areaScope"; @Autowired private TSysRoleService roleService; @Pointcut("@annotation(com.dechnic.omsdc.server.common.annotation.AreaScope)") public void dataScopePointCut() {} @Before("dataScopePointCut()") public void beforePointCut(JoinPoint jp) throws Throwable { TSysUser user = (TSysUser) SecurityUtils.getSubject().getPrincipal(); if (user.isAdmin()) { return; } // 獲得註解 AreaScope areaScope = getAnnotationLog(jp); if (AREA.equals(areaScope.type())){ this.handleAreaDataScope(jp,areaScope.tableAlias(),areaScope.tableColumn()); }else if (AREA_ForReport.equals(areaScope.type())){ this.handleAreaDataScopeForReport(jp,areaScope.tableAlias(),areaScope.tableColumn()); } } private void handleAreaDataScope(JoinPoint jp,String alias,String col) throws Exception { TSysUser user = (TSysUser) SecurityUtils.getSubject().getPrincipal(); if (user == null){ log.info("areaScopeAOP========================user 為null"); }else{ List<TSysRole> roleList = user.getRoleList(); if (roleList == null || roleList.size() == 0) { roleList = roleService.getUserRoleInfo(user.getId(), TSysPerm.PERM_TYPE.MENU); if(roleList == null || roleList.size()==0){ throw new AuthenticationException(user.getUserName()+"尚未分配角色,請聯絡管理員!"); } user.setRoleList(roleList); } } Object obj = jp.getArgs()[0]; // BaseEntity entity = (BaseEntity) jp.getArgs()[0]; for (TSysRole role : user.getRoleList()) { if (TSysRole.PERM_TYPE.ALL.equals(role.getDeptPermType())) { return; } } if (Config.provinceCode.equals(user.getAreaCode())){// 省使用者不做校驗 return; } String aliasCond = ""; if (!StringUtils.isNotEmpty(col)){ throw new Exception("區域資料許可權註解,區域area_code列名不能為空!"); } if (StringUtils.isNotEmpty(alias)){ aliasCond = alias + "." ; } if (obj instanceof Map){ Map map = (Map) obj; String sql = String.format( "and %s%s ='%s' AND %sF_BuildGroupID in (" + "SELECT p.resource_id from t_sys_perm p INNER JOIN " + "t_sys_role_perm rp on p.id = rp.perm_id " + "INNER JOIN t_sys_role r on rp.role_id = r.id " + "INNER JOIN t_sys_user_role ur ON r.id = ur.role_id " + "INNER JOIN t_sys_user u ON ur.user_id = u.id " + "AND u.id ='%s' " + "AND p.perm_type='CORP')", aliasCond,col,user.getAreaCode(),aliasCond,user.getId()); map.put(AREA_SCOPE,sql); }else { BaseEntity entity = (BaseEntity) obj; String sql = String.format( "and %s%s ='%s' AND %sF_BuildGroupID in (" + "SELECT p.resource_id from t_sys_perm p INNER JOIN " + "t_sys_role_perm rp on p.id = rp.perm_id " + "INNER JOIN t_sys_role r on rp.role_id = r.id " + "INNER JOIN t_sys_user_role ur ON r.id = ur.role_id " + "INNER JOIN t_sys_user u ON ur.user_id = u.id " + "AND u.id ='%s' " + "AND p.perm_type='CORP')", aliasCond,col,user.getAreaCode(),aliasCond,user.getId()); entity.getParams().put(AREA_SCOPE,sql); } /*if (obj instanceof Map){ Map map = (Map) obj; String sql = String.format( "and %s%s ='%s'", aliasCond,col,user.getAreaCode()); map.put(AREA_SCOPE,sql); }else { BaseEntity entity = (BaseEntity) obj; String sql = null; sql = String.format( "and %s%s ='%s'", aliasCond,col,user.getAreaCode()); entity.getParams().put(AREA_SCOPE,sql); }*/ } private void handleAreaDataScopeForReport(JoinPoint jp,String alias,String col) throws Exception { TSysUser user = (TSysUser) SecurityUtils.getSubject().getPrincipal(); if (user == null){ log.info("areaScopeAOP========================user 為null"); }else{ List<TSysRole> roleList = user.getRoleList(); if (roleList == null || roleList.size() == 0) { roleList = roleService.getUserRoleInfo(user.getId(), TSysPerm.PERM_TYPE.MENU); if(roleList == null || roleList.size()==0){ throw new AuthenticationException(user.getUserName()+"尚未分配角色,請聯絡管理員!"); } user.setRoleList(roleList); } } // BaseEntity entity = (BaseEntity) jp.getArgs()[0]; for (TSysRole role : user.getRoleList()) { if (TSysRole.PERM_TYPE.ALL.equals(role.getDeptPermType())) { return; } } if (Config.provinceCode.equals(user.getAreaCode())){// 省使用者不做校驗 return; } Object obj = jp.getArgs()[0]; if (obj instanceof Map){ Map map = (Map) obj; map.put("areaCode",user.getAreaCode()); } } /** 是否存在註解,如果存在就獲取 */ private AreaScope getAnnotationLog(JoinPoint joinPoint) { Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); if (method != null) { return method.getAnnotation(AreaScope.class); } return null; } }

(2)配置註解annotation

package com.dechnic.omsdc.server.common.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AreaScope {
    public String type() default "area";
    public String tableAlias() default "";
    public String tableColumn() default "area_code";
}

(3).在方法上使用註解

package com.dechnic.omsdc.server.common.service.impl;

import com.dechnic.omsdc.server.common.annotation.AreaScope;
import com.dechnic.omsdc.server.common.annotation.DataScope;
import com.dechnic.omsdc.server.common.entity.VBuildGroupInfo;
import com.dechnic.omsdc.server.common.mapper.VBuildGroupInfoMapper;
import com.dechnic.omsdc.server.common.service.IVBuildGroupInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service
public class VBuildGroupInfoServiceImpl implements IVBuildGroupInfoService {

    @Autowired
    VBuildGroupInfoMapper vBuildGroupInfoMapper;

    @Override
    @AreaScope(tableAlias = "g")
    @DataScope(type = "corp",tableAlias = "g",tableColumn = "F_BuildGroupID")
    public List<VBuildGroupInfo> selectByMap(Map<String, Object> map) {
        return vBuildGroupInfoMapper.selectByMap(map);
    }
}

(4)在mybatis 的xml 方法裡新增${areaScope}

<select id="selectByMap" parameterType="map" resultMap="BaseResultMap">
    SELECT
    g.*, d.F_Name AS fBuildFuncName
    FROM
    V_BuildGroupInfo g
    inner JOIN (
    SELECT
    *
    FROM
    T_BD_ReferDict
    WHERE
    F_Type = 'BFunc'
    ) d ON g.F_BuildGroupFunc = d.F_code
    ${areaScope}
    <if test="fBuildgroupname !=null and fBuildgroupname !=''">
      and g.F_BuildGroupName like '%'+#{fBuildgroupname}+'%'
    </if>
    <if test="groupIds != null">
      and g.F_BuildGroupID in
      <foreach collection="groupIds" item="item" separator="," open="(" close=")">
        #{item}
      </foreach>
    </if>
    ${dataScope}
    <!--<if test="fBuildfunc  != null and fBuildfunc.size()>0">-->
      <!--and ( 1!=1-->
      <!--<foreach collection="fBuildfunc" item="item" index="index">-->
        <!--or b.F_BuildFunc = #{item}-->
      <!--</foreach>-->
      <!--)-->
    <!--</if>-->
  </select>