悟红尘:zhuanlan.zhihu.com
在我们的项目中和后台的通信的时候,为了防止别人截获并篡改信息,于是决定启用一套自己验签规则,那就是将所有属性的值拼接起来进行SHA256签名,在这个字符串拼接的时候如果属性少还好,直接写一个方法将属性值拼接起来就好了,但是如果属性很多的话,并且需要多次不同的数据与后台进行交互,每次写个方法拼接太麻烦了,为了造福后来者,使拼接变得简单,所以用注解进行了优化。
注解是的作用是在类或者方法,属性等上面打上一个标签,然后通过java的反射机制动态的对打上标签的内容进行解析和处理。
在Java中已经内置了几个注解,我们平常可能有看到:
@Override 用在方法上,表示要覆盖父类中的方法
@Deprecated 表示被弃用的代码,如果使用了被他标注的方法会提示警告
@SuppressWarnings,关闭不当编译器警告信息。
我们可以使用元注解自定义自己的注解,首先需要明白什么是元注解,元注解是java中用于标示注解的注解,java中元注解分为:@Retention、 @Target、 @Document、 @Inherited和@Repeatable
@Retention
标示的是注解存留的阶段,有一个枚举类:
RetentionPolicy.SOURCE 仅存于源码中
RetentionPolicy.CLASS 存在于字节码中,但是在运行是无法获得
RetentionPolicy.RUNTIME 在运行是可以通过反射获得,前面也说过注解的目的是通过反射机制动态的获取值,那么我们最常用的那肯定就是这个了
@Target
目标的意思,是说我们制定的注解是用于什么地方,比如方法,属性,还是类等,同样有一个枚举:
ElementType.TYPE 表示可以作用于类,方法,枚举
ElementType.FIELD 作用于属性
ElementType.METHOD 作用于方法
。。。还有其他的就不说了,反正也不常用,用的时候再看吧
@Documented
它的意思是文档,作用是能将注解包含的Javadoc中去,其实要是用工具javadoc生成文档的时候用,不需要搞什么文档的话,加不加没啥区别
@Inherited
继承的意思,就是子类如果没有其他别的注解的话,可以继承父类标注的注解
@Repeatable
Repeatable的英文意思是可重复的。顾名思义说明被这个元注解修饰的注解可以同时作用一个对象多次,但是每次作用注解又可以代表不同的含义。
好了,那下面我们说说我们最上面说的签名的优化,首先定义注解:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ValidateValue {
//是否参与验证
boolean isValidate() default false;
//排序值
int sortValue() default 0;
}
接着利用反射,根据顺序拼接字符串:
public static String getValue(Object object){
Class aClass = object.getClass();
//获取所有声明的属性
Field[] declaredFields = aClass.getDeclaredFields();
//过滤出所有带有注解的属性
List fields = new ArrayList<>();
for (Field field : declaredFields){
if(field.isAnnotationPresent(ValidateValue.class)){
ValidateValue annotation = field.getAnnotation(ValidateValue.class);
if(annotation.isValidate()){
fields.add(field);
}
}
}
//根据定义的顺序排序
Collections.sort(fields, (o1, o2) -> {
ValidateValue annotation1 = o1.getAnnotation(ValidateValue.class);
ValidateValue annotation2 = o2.getAnnotation(ValidateValue.class);
return annotation1.sortValue() - annotation2.sortValue();
});
StringBuilder sb = new StringBuilder();
for (Field field : fields){
field.setAccessible(true);
try {
//获取属性的值,因为都是基本类型,并且拼的是字符串,所以不用判断获得值是什么类型,直接用object即可
Object value = field.get(object);
sb.append(value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return sb.toString();
}
好了 我们测试下,先定义个bean:
public class Student {
@ValidateValue(isValidate = true, sortValue = 0)
private String address;
@ValidateValue(isValidate = true, sortValue = 2)
private String name;
@ValidateValue(isValidate = true, sortValue = 1)
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
public static void main(String[] args) {
Student student = new Student();
student.setAge(100);
student.setName("小明");
student.setSex("男");
student.setAddress("上海");
System.out.println(getValue(student));
}
结果是: 上海男小明
因为地址的sort为0,sex的sort为1,那么的sort为2
OK 完成