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

前言

公司前端项目用的是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>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值