SpringAop之静态代理AspectJ

最近一段时间,用到了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>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring AOP中,实现静态代理可以使用代理工厂类来创建代理对象。静态代理是指在编译时期就确定代理的目标对象,并手动编写代理类来对目标对象的方法进行增强。通过实现同一个接口或继承同一个父类,代理类可以通过代理对象调用目标对象的方法,并在方法执行前后添加额外的功能。 在Spring AOP中,可以通过配置文件或注解的方式来定义切面(Aspect)和通知(Advice)。切面定义了要对哪些目标对象的方法进行增强,通知定义了在何时执行增强操作。静态代理可以在切面中直接调用目标对象的方法,并在方法执行前后添加增强逻辑。 使用静态代理有一些优点,比如可以在编译时期就确定代理对象和增强逻辑,对于一些稳定的业务逻辑适用。然而,静态代理也存在一些局限性,比如需要手动编写代理类,当目标对象的方法发生变化时,需要手动修改代理类的代码。 总结来说,Spring AOP实现静态代理可以通过配置切面和通知来实现,在切面中编写代理类并调用目标对象的方法来实现增强逻辑。这种方式适用于一些稳定的业务逻辑,但需要手动编写代理类。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Spring aop静态代理 动态代理 Aspectj aop-config 等实现方式](https://download.csdn.net/download/managementandjava/9960807)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [SpringAOP静态代理、动态代理:JDK/CGLIB】](https://blog.csdn.net/qq_45037155/article/details/128906868)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值