在优化代码的时候发现,传参存在着高度冗余,如果后面需要改参数,很不方便。
String pam1 = "id=" + appKey + "&sign=" + sign + "&method=" + method + "&access_token=" + token + "×tamp="
+ timestamp + "&projectCode=" + projectCode;
参考网上的方法,自己创建注解类,利用反射注入参数并实现。
这里解释一下注解。
- @Retention修饰注解,用来表示注解的生命周期
上面三种类型生命周期:SOURCE<CLASS<RUNTIME,使用RUNTIME会包含前面两个生命周期
那怎么来选择合适的注解生命周期呢?
首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要 在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife) ,就用 CLASS注解;如果 只是做一些检查性的操作,比如 @Override 和@SuppressWarnings,则 可选用 SOURCE 注解。
RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。 - @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)——包 - @Inherited:说明子类可以继承父类中的该注解
- @Document 是 java 在生成文档,是否显示注解的开关
第二步是创建实体类,并导入注解,定义导出时的字段名(name)和拼接顺序(order)
第三步就是写出拼接的方法
public class UrlUtil {
public static String createURL(DeviceDTO deviceDTO){
deviceUrl deviceUrl = deviceDTO.getClass().getAnnotation(deviceUrl.class);
StringBuilder stringBuilder = new StringBuilder(deviceUrl.url());
Arrays.stream(deviceDTO.getClass().getDeclaredFields())
.filter(x -> x.isAnnotationPresent(deviceField.class))
.sorted(Comparator.comparing(x -> x.getAnnotation(deviceField.class).order()))
.peek(x -> x.setAccessible(true))
.forEach(field -> {
deviceField flightQueryField = field.getAnnotation(deviceField.class);
Object value = "";
try {
value = field.get(deviceDTO);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (flightQueryField.order() == 1) {
stringBuilder.append("?").append(flightQueryField.name() + "=" + value).append("&");
} else {
stringBuilder.append(flightQueryField.name() + "=" + value).append("&");
}
});
return stringBuilder.toString().substring(0, stringBuilder.toString().length() - 1);
}
}
如果需要实现传入任意类型的类,可以这样实现:
这里,我的url拼接,不需要?,我把append(?)去掉了,若需要自己加上
public static <T> String createURL(Class<T> tClass,T cla){
//将传过来的对象进行赋值处理
T u = tClass.cast(cla);
//以下是验证此示意中实体类可被操作了
//getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
//.getClass()是一个对象实例的方法,只有对象实例才有这个方法,具体的类是没有的
for (Field declaredField : u.getClass().getDeclaredFields()) {
//允许获取实体类private的参数信息
declaredField.setAccessible(true);
}
deviceUrl deviceUrl = cla.getClass().getAnnotation(deviceUrl.class);
StringBuilder stringBuilder = new StringBuilder(deviceUrl.url());
//通过自定义注解deviceField获取实体类的字段值和属性值
Arrays.stream(cla.getClass().getDeclaredFields())
.filter(x -> x.isAnnotationPresent(deviceField.class))
.sorted(Comparator.comparing(x -> x.getAnnotation(deviceField.class).order()))
.peek(x -> x.setAccessible(true))
.forEach(field -> {
deviceField flightQueryField = field.getAnnotation(deviceField.class);
Object value = "";
try {
value = field.get(cla);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (flightQueryField.order() == 1) {
stringBuilder.append(flightQueryField.name() + "=" + value).append("&");
} else {
stringBuilder.append(flightQueryField.name() + "=" + value).append("&");
}
});
return stringBuilder.toString().substring(0, stringBuilder.toString().length() - 1);
}
传参的话是这样的
进行测试
结果
这里我没有加前置的url,在实体类的注解里url加上就好了