前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自定义注解:springboot+vue-限制接口调用

自定义注解:springboot+vue-限制接口调用

作者头像
JAVA葵花宝典
发布2019-09-17 16:25:29
5680
发布2019-09-17 16:25:29
举报

前言

公司前端项目用的是vue,后端用的是Springboot。因为最近公司业务的原因,需要根据条件限制接口的调用。限制的条件是根据指定的key获取Redis中value的值,然后判断value中的日期往后推一年(例如value中的日期是:2018-09-12,往后推一年就是2019-09-12)是否大于当前日期。如果大于则可访问(这里的可访问指的是可访问所有接口)。反之,则所有接口不可访问。

在使用自定义注解之前,我们先来了解Java为我们提供的元注解和相关定义注解的语法。

一、了解Java注解语法

1.元注解(meta-annotation)

元注解的作用就是负责注解其他注解,在java.lang.annotation包中可以找到。

  1. @Target
  2. @Retention
  3. @Documented
  4. @Inherited

二、每个元注解的作用

1.@Target:

用于描述注解的使用范围。

参数说明:

@Target(ElementType.TYPE) //接口、类、枚举、注解 @Target(ElementType.FIELD) //字段、枚举的常量 @Target(ElementType.METHOD) //方法 @Target(ElementType.PARAMETER) //方法参数 @Target(ElementType.CONSTRUCTOR) //构造函数 @Target(ElementType.LOCAL_VARIABLE) //局部变量 @Target(ElementType.ANNOTATION_TYPE) //注解 @Target(ElementType.PACKAGE) //包

2.@Retention

表示需要在什么级别保存该注释信息,用于描述注解的生命周期。

RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃。 RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期。 RetentionPolicy.RUNTIME:注解在运行时有效(运行时保留)。

3.@Documented

Documented是一个标记注解,没有成员。

4.@Inherited

@Inherited 表示该注解会被子类继承。仅针对类,成员属性、方法并不受此注释的影响。对于类来说,子类要继承父类的注解需要该注解被 @Inherited 标识。对于成员属性和方法来说,非重写的都会保持和父类一样的注解,而被实现的抽象方法,被重写的方法都不会有父类的注解。

5.自定义注解

使用@interface自定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型。

三、自定义注解

import java.lang.annotation.*;/** *定制一个接口 */@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface EnableAuth {}
    public class ApiAuthDataInit implements ApplicationContextAware {
        /** 存放需要权限拦截的接口uri */        public static List<String> checkApis = new ArrayList<>();
        @Override            public void setApplicationContext(ApplicationContext ctx) throws BeansException {                Map<String, Object> beanMap = ctx.getBeansWithAnnotation(RestController.class);                if (beanMap != null) {                    for (Object bean : beanMap.values()) {                        Class<?> clz = bean.getClass();                        Method[] methods = clz.getMethods();                        for (Method method : methods) {                            if (method.isAnnotationPresent(EnableAuth.class)) {                                String uri = getApiUri(clz, method);                                checkApis.add(uri);                            }                        }                    }                }            }
            private String getApiUri(Class<?> clz, Method method) {                StringBuilder uri = new StringBuilder();                uri.append(clz.getAnnotation(RequestMapping.class).value()[0]);                if (method.isAnnotationPresent(GetMapping.class)) {                    uri.append(method.getAnnotation(GetMapping.class).value()[0]);                } else if (method.isAnnotationPresent(PostMapping.class)) {                    uri.append(method.getAnnotation(PostMapping.class).value()[0]);                }//                else if (method.isAnnotationPresent(PutMapping.class)) {//                    uri.append(method.getAnnotation(PutMapping.class).value()[0]);//                }else if (method.isAnnotationPresent(DeleteMapping.class)) {//                    uri.append(method.getAnnotation(DeleteMapping.class).value()[0]);//                }                else if (method.isAnnotationPresent(RequestMapping.class)) {                    uri.append(method.getAnnotation(RequestMapping.class).value()[0]);                }                return uri.toString();            }
        }

当一个类实现了ApplicationContextAware接口之后,Spring容器会自动检测所有的Bean,如果发现某个Bean实现了ApplicationContextAware接口,Spring容器就会在创建了该Bean之后,自动调用该Bean的setApplicationContextAware()方法。

在setApplicationContextAware()方法中获取所有带有@RestController注解的类,并获取该类下所有带有@EnableAuth注解的方法,获取该方法@RequestMapping的uri路径,并将uri存入checkApis中。

public class ApiFilter implements Filter {    @Autowired    private  RedisService redisService;
    @Override    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)            throws IOException, ServletException {        HttpServletRequest req = (HttpServletRequest) request;        HttpServletResponse resp = (HttpServletResponse) response;        resp.setCharacterEncoding("utf-8");        resp.setContentType("application/json;charset=utf-8");        // 判断checkApis中是否包含当前请求的uri        if (ApiAuthDataInit.checkApis.contains(req.getRequestURI())) {            String key = "Devices:xxxxxxx";            CarsDto carsDto = redisService.getCar(key);            Calendar c = Calendar.getInstance();            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");            String time = carsDto.getDevFixTime().substring(0,10);            Date date = null;            try {                date = sdf.parse(time);            } catch (ParseException e) {                e.printStackTrace();            }            //设置日历时间            c.setTime(date);            c.add(Calendar.MONTH,18);            String strDate = sdf.format(c.getTime());            String nowDate = sdf.format(new Date());                long nowTime = Long.valueOf(nowDate.replaceAll("[-\\s:]",""));                long carTime = Long.valueOf(strDate.replaceAll("[-\\s:]",""));                if (nowTime > carTime) {                   return;                }        }        chain.doFilter(request, response);    }
    @Override    public void destroy() {
    }
}

定义了注解,并在需要的时候给相关类,类属性加上注解信息,如果没有响应的注解信息处理流程,注解可以说是没有实用价值。

四、使用自定义注解

   @EnableAuth   @PostMapping(value = "/login")  public ResultData login(String username,  String password) {        logger.info("------用户登录 login:{}   start", "username:" + username + "password:" + password);        User user = userDao.findByUserName(username);        if (user == null) {            logger.info("------user == null");            return ResultData.bizError(ResultMessage.USER_NOT_FIND);        }        if (!user.getStatus().equals(UserStatus.ACTIVE.getCode())) {            logger.info("------user已删除");            return ResultData.bizError(ResultMessage.USER_NOT_FIND);//被禁止的异常        }        if (!loginService.checkUser(user, password)) {            logger.info("------用户名或密码不正确");            return ResultData.bizError(ResultMessage.USER_PASSWORD_EQUAL);        }        // 设置登陆时间        logger.info("------更新登录时间");        loginService.setLoginTime(user);        logger.info("------用户登录 login:{} 登录成功", "user:" + new Gson().toJson(user));        LoginUser loginUser = new LoginUser();      //略
        logger.info("------用户登录 login:{}   end", "loginUser:" + new Gson().toJson(loginUser));        return ResultData.ok().putDataValue("User", loginUser);    }

五、vue部分代码

<template>    <div id="login">        <div class="loginBox">            <div class="loginForm">                <div class="formHeader">                    <span class="title">欢迎登录</span>                </div>                <el-form :model="loginForm" ref="loginForm" :rules="loginFormRule">                    <el-form-item label="" prop="username">                        <i class="iconfont icon-touxiang"></i>                        <el-input v-model="loginForm.username" placeholder="用户名" auto-complete="off"></el-input>                    </el-form-item>                    <el-form-item label="" prop="password">                        <i class="iconfont icon-mima"></i>                        <el-input v-model="loginForm.password" placeholder="密码" type="password" auto-complete="off"></el-input>                    </el-form-item>                    <el-form-item>                        <el-button class="loginBtn" type="primary" @click="login">登录</el-button>                    </el-form-item>                </el-form>            </div>        </div>    </div></template>
<script>
    export default {        data () {           //略        },       //略        methods: {            //略            login(){                this.$refs['loginForm'].validate((valid) => {                    if(valid){                        this.api.login(this.loginForm).then((res)=> {                            if (res.data.code=='OK') {                                this.$message({                                    type:'success',                                    message:'登录成功!'                                });                                this.$store.commit('signIn', res.data.data.User);                            } else {                                this.$message.error(res.data.message);                            }                        }).catch((res)=>{                                this.$message.error(res);                        });                    }                });            }        }    }</script>
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JAVA葵花宝典 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档