简介
最近在处理对接易宝支付。易宝支付有的接口需要传递签名(hmac 字段),但是每个接口的签名字段不一样,所以每个接口都需要传递一个string 数组,用来对数组中的字段进行签名,并且签名字段是有顺序的。
思路
因为每个接口的参数我都封装了对应的DTO,比如下订单接口,我封装了一个TokenDTO,支付接口,我封装了一个PayDTO,想要定义一个自定义注解,注解标记在字段上。通过对应的参数类反射来获取对应的加密字段。
实现
首先,需要有个注解,标记在字段上。
import java.lang.annotation.*;
/**
* 标记字段需要被签名
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface HmacField {
/**
* 加密字段的顺序,从小到大
*
* @return
*/
int sort();
}
YeePayUtils.java 包含了一些通用的请求以及解析方法,所以将处理直接放在了该帮助类中了,对应的 HamcFieldSortHelper 作为一个内部类处理。
/**
* 参与签名的字段缓存 map<类的全路径名,需要签名的字段列表>
*/
private static Map<String, List<String>> hmacFiledCacheMap = new ConcurrentHashMap<>();
/**
* 获取某个类需要加密的字段列表,注意顺序以及对应类的父类字段的顺序
*
* @param clazz 参数类,注意父类字段也会获取
* @return
*/
public static List<String> getHmacFileds(Class clazz) {
List<String> res = new ArrayList<>();
List<Field> fieldList = ReflectionKit.getFieldList(Objects.requireNonNull(clazz));
String fullName = clazz.getPackage().getName() + clazz.getSimpleName();
List<String> cacheFields = hmacFiledCacheMap.get(fullName);
if (CollectionUtils.isNotEmpty(cacheFields)) {
return cacheFields;
}
if (CollectionUtils.isNotEmpty(fieldList)) {
List<HamcFieldSortHelper> hamcFieldSortHelperList = new ArrayList<>();
fieldList.stream().filter(field -> field.getAnnotation(HmacField.class) != null).forEach(item -> hamcFieldSortHelperList.add(new HamcFieldSortHelper().setName(item.getName()).setSort(item.getAnnotation(HmacField.class).sort())));
res = hamcFieldSortHelperList.stream().sorted(Comparator.comparing(HamcFieldSortHelper::getSort)).map(HamcFieldSortHelper::getName).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(res)) {
hmacFiledCacheMap.put(fullName, res);
}
}
return res;
}
/**
* 因为加密字段有顺序,该类用来帮助排序
*/
@Data
@Accessors(chain = true)
static class HamcFieldSortHelper implements Serializable {
String name;
int sort;
}
使用,在类上标记注解,注意顺序以及父类字段(本想加一个callback 来reset 字段,但是感觉可能用到的情况不会很多,如果有特殊字段以及处理就自行修改list吧)
@Data
@Accessors(chain = true)
@ApiModel(value = "MerchantDTO", description = "门店基类")
public class MerchantDTO extends BaseDTO {
@HmacField(sort = 1)
@ApiModelProperty(value = "代理商编号", hidden = true)
private String parentMerchantNo;
@HmacField(sort = 2)
@ApiModelProperty("子商编号")
private String merchantNo;
}