sa-token/sa-token-doc/fun/custom-annotations.md
2024-08-29 21:48:49 +08:00

200 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 自定义注解
如果框架内置的注解无法满足你的业务需求,你还可以自定义注解注入到框架中。
---
### 1、自定义注解
假设有以下业务需求
> [!INFO| label:需求场景]
> 自定义一个注解 `@CheckAccount`,具有 `name`、`pwd` 两个字段,在标注一个方法上时,要求前端必须提交相应的账号密码参数才能访问方法。
#### 1.1、第一步,创建一个注解
``` java
/**
* 账号校验:在标注一个方法上时,要求前端必须提交相应的账号密码参数才能访问方法。
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE})
public @interface CheckAccount {
/**
* 需要校验的账号
*/
String name();
/**
* 需要校验的密码
*/
String pwd();
}
```
#### 1.2、第二步,创建注解处理器
实现 `SaAnnotationHandlerInterface` 接口,指定泛型为刚才自定义的注解
``` java
/**
* 注解 CheckAccount 的处理器
*/
@Component
public class CheckAccountHandler implements SaAnnotationHandlerInterface<CheckAccount> {
// 指定这个处理器要处理哪个注解
@Override
public Class<CheckAccount> getHandlerAnnotationClass() {
return CheckAccount.class;
}
// 每次请求校验注解时,会执行的方法
@Override
public void checkMethod(CheckAccount at, AnnotatedElement element) {
// 获取前端请求提交的参数
String name = SaHolder.getRequest().getParamNotNull("name");
String pwd = SaHolder.getRequest().getParamNotNull("pwd");
// 与注解中指定的值相比较
if(name.equals(at.name()) && pwd.equals(at.pwd()) ) {
// 校验通过,什么也不做
} else {
// 校验不通过,则抛出异常
throw new SaTokenException("账号或密码错误,未通过校验");
}
}
}
```
参考上述代码,实现类上指定了 `@Component` 注解,使其可以在 ioc 环境下(如 Spring被自动扫描注册 Sa-Token 中,
如果你的项目属于非 ioc 环境,则需要手动将其注册到 Sa-Token 框架中:
``` java
SaAnnotationStrategy.instance.registerAnnotationHandler(new CheckAccountHandler());
```
#### 1.3、测试自定义的注解
我们在一个请求接口上指定这个注解,来测试一下效果
``` java
@RestController
@RequestMapping("/test/")
public class TestController {
@RequestMapping("test")
@CheckAccount(name = "sa", pwd = "123456")
public SaResult test() {
System.out.println("------------进来了");
return SaResult.ok();
}
}
```
启动项目,使用浏览器访问此接口。
先来个错误的账号密码访问测试一下:[http://localhost:8081/test/test?name=sa&pwd=123](http://localhost:8081/test/test?name=sa&pwd=123)
返回结果:
``` js
{
"code": 500,
"msg": "账号或密码错误,未通过校验",
"data": null
}
```
使用正确账号密码测试访问:[http://localhost:8081/test/test?name=sa&pwd=123456](http://localhost:8081/test/test?name=sa&pwd=123456)
返回结果:
``` js
{
"code": 200,
"msg": "ok",
"data": null
}
```
### 2、使用自定义注解优化多账号鉴权
在之前的 [ 多账号鉴权 ] 章节,我们介绍了利用 “spring 注解处理器” 达到注解合并的目的,从而简化多账号体系下的注解鉴权写法。
此种方案比较简单,但是也有一些缺点。
- 1、强依赖 Spring无法在非 Spring 环境中使用。
- 2、注解递归检查可能会造成一些性能下降。
- 3、扩展性较低只能略微简化框架内置好的注解写法无法灵活扩展功能。
此处我们再演示一种方案,使用自定义注解的方式达到相同的目的。
#### 2.1、首先定义注解
``` java
/**
* 登录认证(User版):只有登录之后才能进入该方法
* <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE})
public @interface SaUserCheckLogin {
}
```
#### 2.2、定义注解处理器
``` java
/**
* 注解 SaUserCheckLogin 的处理器
*/
@Component
public class SaUserCheckLoginHandler implements SaAnnotationHandlerInterface<SaUserCheckLogin> {
@Override
public Class<SaUserCheckLogin> getHandlerAnnotationClass() {
return SaUserCheckLogin.class;
}
@Override
public void checkMethod(SaUserCheckLogin at, AnnotatedElement element) {
SaCheckLoginHandler._checkMethod(StpUserUtil.TYPE);
}
}
```
#### 2.3、使用新注解
接下来就可以使用我们的自定义注解了:
``` java
// 使用 @SaUserCheckLogin 的效果等同于使用:@SaCheckLogin(type = "user")
@SaUserCheckLogin
@RequestMapping("info")
public String info() {
return "查询用户信息";
}
```
注:其它注解 `@SaCheckRole("xxx")`、`@SaCheckPermission("xxx")` 同理, 完整示例参考 Gitee 代码:
[自定义注解](https://gitee.com/dromara/sa-token/tree/master/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/satoken/custom_annotation)。