spring自定义注解+aop+@BindingParam

这篇具有很好参考价值的文章主要介绍了spring自定义注解+aop+@BindingParam。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.pom 引入

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2.声明自定义注解

2.1 声明切面注解

import java.lang.annotation.*;

/**
 * @author WANGCHENG
 * @version 1.0
 * @Description: 校验组合编辑权限注解
 * @date 2023/08/04 20:12
 */
@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckInstructionAuth {
    /**
     * 指令类型  默认:销售
     */
    CheckInstructionEditTypeEnum instructionType()
            default CheckInstructionEditTypeEnum.SALE;

    /**
     * 操作类型,必选,用来错误提示。
     * eg:选择修改,校验提示:没有XX组合的操作权限,不允许修改
     *
     * @return
     */
    CheckInstructionEditTypeEnum.OperateTypeEnum operateType();

    /**
     * 校验数据类型   默认:当前数据
     */
    CheckInstructionEditTypeEnum.CheckDataTypeEnum checkDataType()
            default CheckInstructionEditTypeEnum.CheckDataTypeEnum.CURRENT;

    /**
     * 获取数据方式,默认:@BindingParam 标注
     */
    CheckInstructionEditTypeEnum.DataSourceEnum dataSource()
            default CheckInstructionEditTypeEnum.DataSourceEnum.ANNOTATION;


    /**
     * 是否立即清除副本,默认立即清除副本数据。
     * 如果获取数据方式为 THREAD_LOCAL,后续还需要使用该参数,开发自行清除
     */
    boolean isFlushThreadLocal() default true;

 2.1.1切面对应枚举

@AllArgsConstructor
public enum CheckInstructionEditTypeEnum {
    SALE("SALE","销售", "2"),
    MARKET("MARKET","做市", "1"),
    BID("BID","中标", "2");
    private String instructionCode;
    /**
     * 功能名称
     */
    private String name;
    /**
     * 组合分类标签值
     */
    private String orgType;

    public String getInstructionCode() {
        return instructionCode;
    }

    public String getName() {
        return name;
    }

    public String getOrgType() {
        return orgType;
    }

    /**
     * 参数类型来源
     * DEFAULT_KEY    入参 根据对象的默认key 反射获取,pid,pidList,pids,userId
     * ANNOTATION   入参根据注解获取 和 @BindingParam 配合使用,可以是方法入参注解或者属性注解 ,推荐使用
     * THREAD_LOCAL  副本(需要提前塞值)
     */
    public enum DataSourceEnum {
        DEFAULT_KEY,ANNOTATION,THREAD_LOCAL
    }

    /**
     * DataSourceEnum 为 DEFAULT_KEY 时,默认获取的key
     */
    public enum DataSourceDefaultKeyEnum {
        pid,pidList,pids,userId
    }

    /**
     *   CURRENT 校验当前数据
     *   GROUP   校验整组数据,eg:索引号,code。组合下达指令时,可能 会整组索引指令下达,需校验整组数据
     */
    public enum CheckDataTypeEnum{
        CURRENT,GROUP
    }

    /**
     * 操作类型,用来错误信息提示
     */
    @AllArgsConstructor
    public enum OperateTypeEnum{
        ADD("ADD","新增"),
        UPDATE("UPDATE","修改"),
        DELETE("DELETE","删除"),
        RELEASE("RELEASE","下达"),
        DECILITER("DECILITER","拆合单");
        private String code;
        private String name;

        /**
         * 操作 code
         * @return
         */
        public String getCode() {
            return code;
        }
        /**
         * 操作名称
         * @return
         */
        public String getName() {
            return name;
        }
    }
}
 2.2 声明绑定参数注解
/**
 * @author WANGCHENG
 * @version 1.0
 * @Description: 标注入参的数据类型,配合检验组合权限
 * @date 2023/08/04 20:12
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface BindingParam {
    BindingParamTypeEnum value();
}

绑定参数对应枚举

public enum BindingParamTypeEnum {
    pid,pidList,userId,isConfirm
}

3 切面逻辑


@Aspect
@Component
@Slf4j
public class CheckInstructionAuthAspect {
    // 切点
    @Pointcut(value = "@annotation(com.dsd.study.annotion.CheckInstructionAuth)")
    public void pointcut() {}

    /**
     * 切点配置,CheckCombinedEditAuth 注解的地方
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("pointcut()")
    public Object CheckCombinedEditAuth(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        String targetClassName = joinPoint.getTarget().getClass().getCanonicalName();
        String targetMethodName = joinPoint.getSignature().getName();
        String target=targetClassName+"#"+targetMethodName;
        log.info("校验指令权限目标方法为={}",target);
        if(!editAuthSwitch()){
            return joinPoint.proceed();
        }
        //获取方法,此处可将signature强转为MethodSignature
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //参数注解,1维是参数,2维是注解
        CheckInstructionAuth checkInstructionAuth = method.getAnnotation(CheckInstructionAuth.class);
        Object[] args = joinPoint.getArgs();
        log.info("校验指令权限目标方法入参={},={}",target,JSON.toJSONString(args));
        CheckInstructionEditTypeEnum checkInstructionEditTypeEnum = checkInstructionAuth.instructionType();
        Map<String, Object> paramData =new HashMap<>();
        if(CheckInstructionEditTypeEnum.SALE.equals(checkInstructionEditTypeEnum)){
            paramData=analysisDataSource(args,checkInstructionAuth,method);
        }
        log.info("{}校验指令权限解析入参为={}",target,JSON.toJSONString(paramData));
        String userId =(String) paramData.get(BindingParamTypeEnum.userId.name());
        List<String> pidList =(List<String>)paramData.get(BindingParamTypeEnum.pidList.name());
        if(StringUtils.isBlank(userId)){
            log.info("CheckCombinedEditAuthAspect#CheckCombinedEditAuth--->未查询到用户信息");
            throw new BusinessException("未查询到用户信息");
        }
        List<String> userAuthList = getUserAuthList(userId, checkInstructionAuth);
        if(pidList==null || pidList.size()==0){
            log.info("CheckCombinedEditAuthAspect#CheckCombinedEditAuth--->未查询到校验的指令");
            throw new BusinessException("未查询到校验的指令");
        }
        List<String> checkDataList = getCheckData(pidList, checkInstructionAuth);
        //权限对比
        if(!compareAuth(userAuthList,checkDataList)){
            log.info("userId={},权限对比,userAuthList={},checkDataList={}",
                    JSON.toJSONString(userAuthList),JSON.toJSONString(checkDataList));
            checkDataList.removeAll(userAuthList);
            if(checkDataList.size()>0){
                //数据权限大于用户拥有权限
                List<String> combinedNameList = getCombinedNameByVcRemarksKey(checkDataList);
                //没有权限的组合
                String combinedNameListStr = combinedNameList.stream()
                        .collect(Collectors.joining(","));
                String operateName = checkInstructionAuth.operateType().getName();
                log.info("userId={},权限不相等,没有"+combinedNameListStr+"组合的操作权限,不允许{}",userId,operateName);
                //没有XX组合的操作权限,不允许新增
                throw new BusinessException("没有"+combinedNameListStr+"组合的操作权限,不允许"+operateName);
            }
        }
        log.info("{}耗时为={}毫秒",target,System.currentTimeMillis()-startTime);
        return joinPoint.proceed();
    }

    /**
     * 根据组合code获取组合名称
     * @param vcRemarksKeyList
     * @return
     */
    private List<String> getCombinedNameByVcRemarksKey(List<String> vcRemarksKeyList){
        //伪代码
        return new ArrayList<>();
    }

    /**
     * 比较List<string> 是否相等
     * @param userAuthList
     * @param checkDataList
     * @return
     */
    private boolean compareAuth(List<String> userAuthList,List<String> checkDataList){
        if(userAuthList.size()!=checkDataList.size()){
            return false;
        }
        String[] userAuthArry = userAuthList.toArray(new String[]{});
        String[] checkDataArry = checkDataList.toArray(new String[]{});
        Arrays.sort(userAuthArry);
        Arrays.sort(checkDataArry);
        return Arrays.equals(userAuthArry, checkDataArry);
    }
    /**
     * 解析入参数据,拿到需要的入参
     * @param args
     * @return
     */
    private Map<String,Object> analysisDataSource(Object[] args, CheckInstructionAuth checkCombinedEditAuth, Method method)
            throws IllegalAccessException, BusinessException {
        Map<String,Object> result=new HashMap<>();
        String operateId=null;
        List<String> pidList=new ArrayList<>();
        CheckInstructionEditTypeEnum.DataSourceEnum dataSource = checkCombinedEditAuth.dataSource();
        try {
            if(CheckInstructionEditTypeEnum.DataSourceEnum.DEFAULT_KEY.equals(dataSource)){
                //反射,获取默认的 key
                for(Object obj:args){
                    if(obj instanceof Map){
                        Map<String,Object> objMap=(Map<String,Object>)obj;
                        getParamByDefaultKey(objMap,result);
                    }else{
                        //自定义对象默认key
                        Field[] fields = obj.getClass().getDeclaredFields();
                        for(Field field:fields){
                            field.setAccessible(true);
                            String name = field.getName();
                            if(CheckInstructionEditTypeEnum.DataSourceDefaultKeyEnum.userId.name().equals(name)){
                                if(obj instanceof String){
                                    operateId=(String)field.get(obj);
                                }
                            }else if(CheckInstructionEditTypeEnum.DataSourceDefaultKeyEnum.pid.name().equals(name) ||
                                    CheckInstructionEditTypeEnum.DataSourceDefaultKeyEnum.pidList.name().equals(name) ||
                                    CheckInstructionEditTypeEnum.DataSourceDefaultKeyEnum.pids.name().equals(name)){
                                // key 为 pid,pids,pidList
                                if(obj instanceof String){
                                    pidList.add((String)field.get(obj));
                                }else if(obj instanceof List){
                                    pidList.addAll((List)field.get(obj));
                                }
                            }
                        }
                    }
                }
            }else if(CheckInstructionEditTypeEnum.DataSourceEnum.ANNOTATION.equals(dataSource)){
                //注解,入参加注解
                Annotation[][] parameterAnnotations = method.getParameterAnnotations();
                int index = 0;
                for(Annotation[] annotationx:parameterAnnotations){
                    Object param=args[index];
                    for(Annotation annotationy:annotationx){
                        if(annotationy instanceof BindingParam){
                            BindingParam bindingParam=(BindingParam)annotationy;
                            getParamByBindingParam(bindingParam, param,result);
                        }
                    }
                    index++;
                }
                //注解,属性加注解,注意:会覆盖入参注解的取值
                for(Integer i=0;i<args.length;i++){
                    Object obj=args[i];
                    Field[] fields = obj.getClass().getDeclaredFields();
                    for(Field field:fields){
                        field.setAccessible(true);
                        //如果字段上有自定义注解@BindingParam
                        BindingParam bindingParam = field.getAnnotation(BindingParam.class);
                        getParamByBindingParam(bindingParam, field.get(obj),result);
                    }
                }
            }else if(CheckInstructionEditTypeEnum.DataSourceEnum.THREAD_LOCAL.equals(dataSource)){
                operateId = (String) ThreadLocalUtils.get(BindingParamTypeEnum.userId.name());
                List<String> pidListResult = (List<String>)ThreadLocalUtils.get(BindingParamTypeEnum.pidList.name());
                pidList.addAll(pidListResult);
            }
        } catch (BusinessException e) {
            throw e;
        } finally {
            if(CheckInstructionEditTypeEnum.DataSourceEnum.THREAD_LOCAL.equals(dataSource) &&
                    checkCombinedEditAuth.isFlushThreadLocal()){
                ThreadLocalUtils.delete(BindingParamTypeEnum.userId.name());
                ThreadLocalUtils.delete(BindingParamTypeEnum.pidList.name());
            }
        }
        if(StringUtils.isNotBlank(operateId)){
            result.put(BindingParamTypeEnum.userId.name(),operateId);
        }
        if(pidList.size()>0){
            result.put(BindingParamTypeEnum.pidList.name(),pidList);
        }
        return result;
    }

    /**
     * 入参为Map 解析数据
     * @param map
     * @param result
     * @return
     */
    private Map<String,Object> getParamByDefaultKey(Map<String,Object> map,Map<String,Object> result){
        if(map==null){
            return result;
        }
        for(Map.Entry<String,Object> mapx:map.entrySet()){
            String key = mapx.getKey();
            Object value = mapx.getValue();
            if(value==null){
                continue;
            }
            if(CheckInstructionEditTypeEnum.DataSourceDefaultKeyEnum.userId.name().equals(key)){
                if(value instanceof String){
                    result.put(CheckInstructionEditTypeEnum.DataSourceDefaultKeyEnum.userId.name(),(String)value);
                }
            } else if(CheckInstructionEditTypeEnum.DataSourceDefaultKeyEnum.pid.name().equals(key)){
                if(value instanceof String){
                    result.put(CheckInstructionEditTypeEnum.DataSourceDefaultKeyEnum.pidList.name()
                            ,Arrays.asList((String)value));
                }
            } else if(CheckInstructionEditTypeEnum.DataSourceDefaultKeyEnum.pidList.name().equals(key) ||
                    CheckInstructionEditTypeEnum.DataSourceDefaultKeyEnum.pids.name().equals(key)){
                if(value instanceof List){
                    if(value instanceof List){
                        List<Object> objList=(List<Object>)value;
                        if(objList.size()>0 && objList.get(0) instanceof String){
                            result.put(CheckInstructionEditTypeEnum.DataSourceDefaultKeyEnum.pidList.name()
                                    ,(List<String>)value);
                        }
                    }
                }
            }
        }
        return result;
    }

    /**
     * 根据注解获取入参
     * @param bindingParam
     * @param param
     * @return
     */
    private Map<String,Object> getParamByBindingParam(BindingParam bindingParam, Object param, Map<String,Object> result)
            throws BusinessException {
        if(bindingParam==null){
            log.info("没有 @BindingParam 绑定参数");
            return result;
        }
        if(bindingParam!=null){
            BindingParamTypeEnum value = bindingParam.value();
            if(BindingParamTypeEnum.pid.equals(value)){
                if(param instanceof String){
                    result.put(BindingParamTypeEnum.pidList.name()
                            , Arrays.asList((String)param).stream().collect(Collectors.toList()));
                }else{
                    log.info("@BindingParam 注解类型使用错误,pid只能绑定String类型");
                    throw new BusinessException("@BindingParam 注解类型使用错误,pid只能绑定String类型");
                }

            }else if(BindingParamTypeEnum.pidList.equals(value)){
                if(param instanceof List){
                    List<Object> objList=(List)param;
                    if(objList!=null && objList.size()>0){
                        if(objList.get(0) instanceof String){
                            result.put(BindingParamTypeEnum.pidList.name(),(List<String>)param);
                        }else {
                            log.info("@BindingParam 注解类型值使用错误,pidList只能绑定List<String>类型");
                            throw new BusinessException("@BindingParam 注解类型值使用错误,pidList只能绑定List<String>类型");
                        }
                    }
                }else{
                    log.info("@BindingParam 注解类型值使用错误,pidList只能绑定List类型");
                    throw new BusinessException("@BindingParam 注解类型值使用错误,pidList只能绑定List类型");
                }
            }else if(BindingParamTypeEnum.userId.equals(value)){
                if(param instanceof String){
                    result.put(BindingParamTypeEnum.userId.name(),(String)param);
                }else{
                    log.info("@BindingParam 注解类型值使用错误,userId只能绑定String类型");
                    throw new BusinessException("@BindingParam 注解类型值使用错误,userId只能绑定String类型");
                }
            }
        }
        return result;
    }

    /**
     * 用户存在的编辑组合权限
     * @param userId
     * @param checkCombinedEditAuth
     * @return
     */
    private List<String> getUserAuthList(String userId,CheckInstructionAuth checkCombinedEditAuth){
        //获取用户权限,业务代码
        return new ArrayList<>();
    }

    /**
     * 需要校验的组合数据
     * @param pidList
     * @param checkCombinedEditAuth
     * @return
     */
    private List<String> getCheckData(List<String> pidList, CheckInstructionAuth checkCombinedEditAuth){
        CheckInstructionEditTypeEnum checkInstructionEditTypeEnum = checkCombinedEditAuth.instructionType();
        List<String> checkDataList=new ArrayList<>();
        if(CheckInstructionEditTypeEnum.SALE.equals(checkInstructionEditTypeEnum)){
            //获取需要校验的数据
        }
        //校验其它
        return checkDataList;
    }

    /**
     * 校验权限开关,redis 控制。默认开启=1;
     * @return
     */
    private boolean editAuthSwitch(){
        return true;
    }
}

 4涉及的Util 

4.1 ThreadLocalUtil 
public class ThreadLocalUtils {
    private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL =
            ThreadLocal.withInitial(() -> new ConcurrentHashMap<>(16));

    /**
     * 获取到ThreadLocal中值
     *
     * @return ThreadLocal存储的是Map
     */
    public static Map<String, Object> getThreadLocal() {
        return THREAD_LOCAL.get();
    }

    /**
     * 从ThreadLocal中的Map获取值
     *
     * @param key Map中的key
     * @param <T> Map中的value的类型
     * @return Map中的value值 可能为空
     */
    public static <T> T get(String key) {
        return get(key, null);
    }

    /**
     * 从ThreadLocal中的Map获取值
     *
     * @param key          Map中的key
     * @param defaultValue Map中的value的为null 是 的默认值
     * @param <T>          Map中的value的类型
     * @return Map中的value值 可能为空
     */
    @SuppressWarnings("unchecked")
    public static <T> T get(String key, T defaultValue) {
        Map<String, Object> map = THREAD_LOCAL.get();
        if (MapUtils.isEmpty(map)) {
            return null;
        }
        return (T) Optional.ofNullable(map.get(key)).orElse(defaultValue);
    }

    /**
     * ThreadLocal中的Map设置值
     *
     * @param key   Map中的key
     * @param value Map中的value
     */
    public static void set(String key, Object value) {
        Map<String, Object> map = THREAD_LOCAL.get();
        map.put(key, value);
    }

    /**
     * ThreadLocal中的Map 添加Map
     *
     * @param keyValueMap 参数map
     */
    public static void set(Map<String, Object> keyValueMap) {
        Map<String, Object> map = THREAD_LOCAL.get();
        map.putAll(keyValueMap);
    }

    /**
     * 删除ThreadLocal中的Map 中的value
     *
     * @param key Map中的key
     */
    public static void delete(String key) {
        Map<String, Object> map = THREAD_LOCAL.get();
        if (MapUtils.isEmpty(map)) {
            return;
        }
        map.remove(key);
    }

    /**
     * 删除ThreadLocal中的Map
     */
    public static void remove() {
        THREAD_LOCAL.remove();
    }

    /**
     * 从ThreadLocal中的Map获取值 根据可key的前缀
     *
     * @param prefix key 的前缀
     * @param <T>    Map中的value的类型
     * @return 符合条件的Map
     */
    @SuppressWarnings("unchecked")
    public static <T> Map<String, T> fetchVarsByPrefix(String prefix) {
        Map<String, T> vars = new HashMap<>(16);
        if (StringUtils.isBlank(prefix)) {
            return vars;
        }
        Map<String, Object> map = THREAD_LOCAL.get();
        if (MapUtils.isEmpty(map)) {
            return vars;
        }
        return map.entrySet().stream().filter(test -> test.getKey().startsWith(prefix))
                .collect(Collectors.toMap(Map.Entry::getKey, time -> (T) time.getValue()));
    }

    /**
     * 删除ThreadLocal中的Map 中的Value  按 Map中的Key的前缀
     *
     * @param prefix Map中的Key的前缀
     */
    public static void deleteVarsByPrefix(String prefix) {
        if (StringUtils.isBlank(prefix)) {
            return;
        }
        Map<String, Object> map = THREAD_LOCAL.get();
        if (MapUtils.isEmpty(map)) {
            return;
        }
        map.keySet().stream().filter(o -> o.startsWith(prefix)).collect(Collectors.toSet()).forEach(map::remove);
    }
}
4.2  自定义异常
public class BusinessException extends Exception{
    private static final long serialVersionUID = -3463054564635276929L;
    /**
     * 错误码
     */
    private String errCode;

    /**
     * 错误描述
     */
    private String errDesc;

    public BusinessException() {
        super();
    }

    public BusinessException(String errDesc) {
        super(errDesc);
        this.errDesc = errDesc;
    }

    public BusinessException(String errCode, String errDesc) {
        super(errCode);
        this.errCode = errCode;
        this.errDesc = errDesc;
    }

    public String getErrCode() {
        return errCode;
    }

    public String getErrDesc() {
        return errDesc;
    }
}

5 使用示例

@Service
public class TestServiceImpl implements TestService {
    @CheckInstructionAuth(operateType = CheckInstructionEditTypeEnum.OperateTypeEnum.RELEASE)
    @Override
    public void getData(Map<String, Object> map,@BindingParam(BindingParamTypeEnum.pidList) String userId) {
        System.out.println("testAnnotation");
    }


    @CheckInstructionAuth(operateType = CheckInstructionEditTypeEnum.OperateTypeEnum.RELEASE)
    @Override
    public void getData(List<UserDto> userDto) {
        System.out.println("testAnnotation");
    }
}

文章来源地址https://www.toymoban.com/news/detail-634990.html

到了这里,关于spring自定义注解+aop+@BindingParam的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Spring AOP + 自定义注解 + 动态数据源 实现主从库切换&读写分离】—— 案例实战

                                                 💧 S p r i n g A O P + 主从数据源切换 + 读写分离 + 自定义注解案例实战! color{#FF1493}{Spring AOP + 主从数据源切换 + 读写分离 + 自定义注解 案例实战!} Sp r in g A OP + 主从数据源切换 + 读写分离 + 自定义注解案例

    2024年02月15日
    浏览(26)
  • Spring Boot入门(23):基于AOP实现自定义注解拦截接口日志并保存入库 | 超级详细,建议收藏

            在上两期中,我们着重介绍了如何集成使用 Logback 与 log4j2 日志框架的使用,今天我们讲解的主题依旧跟日志有关,不过不是使用何种开源框架,而是自己动手造。         Spring的核心之一AOP;AOP翻译过来叫面向切面编程, 核心就是这个切面. 切面表示从业务逻辑中

    2024年02月11日
    浏览(35)
  • Spring Boot入门(23):记录接口日志再也不难!用AOP和自定义注解给Spring Boot加上日志拦截器!

            在上两期中,我们着重介绍了如何集成使用 Logback 与 log4j2 日志框架的使用,今天我们讲解的主题依旧跟日志有关,不过不是使用何种开源框架,而是自己动手造。         Spring的核心之一AOP;AOP翻译过来叫面向切面编程, 核心就是这个切面. 切面表示从业务逻辑中

    2024年02月11日
    浏览(44)
  • spring boot 使用AOP+自定义注解+反射实现操作日志记录修改前数据和修改后对比数据,并保存至日志表

    使用FieldMeta自定义注解,看个人业务自行觉得是否需要重新定义实体 实现类 :通过该实现类获取更新前后的数据。 该实现类的实现原理为:获取入参出入的id值,获取sqlSessionFactory,通过sqlSessionFactory获取selectByPrimaryKey()该方法,执行该方法可获取id对应数据更新操作前后的数

    2024年01月23日
    浏览(39)
  • springboot aop 自定义注解形式

    2024年01月25日
    浏览(28)
  • 根据aop实现自定义缓存注解

    自定义注解 切面 使用

    2024年02月13日
    浏览(43)
  • 【SpringBoot】AOP 自定义注解的使用详解

            Spring 中的切面 Aspect,这是 Spring 的一大优势。面向切面编程往往让我们的开发更加低耦合,也大大减少了代码量,同时呢让我们更专注于业务模块的开发,把那些与业务无关的东西提取出去,便于后期的维护和迭代。         AOP 的全称为 Aspect Oriented Programming,

    2024年02月05日
    浏览(32)
  • SpringBoot + 自定义注解 + AOP 打造通用开关

    前言 最近在工作中迁移代码的时候发现了以前自己写的一个通用开关实现,发现挺不错,特地拿出来分享给大家。 为了有良好的演示效果,我特地重新建了一个项目,把核心代码提炼出来加上了更多注释说明,希望xdm喜欢。 案例 1、项目结构 2、引入依赖 3、yml配置 连接Re

    2024年01月23日
    浏览(31)
  • 【SpringMVC】自定义注解与AOP结合使用

    目录 一、SpringMVC之自定义注解 1.1 Java注解简介 1.2 为什么要用注解 1.3 注解的分类 ⭐ 1.3.1 JDK基本注解 1.3.2 JDK元注解  1.3.3 自定义注解  1.4 自定义注解三种使用案例 1.4.1 案例一(获取类与方法上的注解值) 1.4.2 案例二(获取类属性上的注解属性值) 1.4.3 案例三(获取参数

    2024年02月07日
    浏览(58)
  • Spring AOP官方文档学习笔记(二)之基于注解的Spring AOP

    1.@Aspect注解 (1) @Aspect注解用于声明一个切面类,我们可在该类中来自定义切面,早在Spring之前,AspectJ框架中就已经存在了这么一个注解,而Spring为了提供统一的注解风格,因此采用了和AspectJ框架相同的注解方式,这便是@Aspect注解的由来,换句话说,在Spring想做AOP框架之前,

    2023年04月17日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包