SpringBoot使用反射对业务代码进行统一处理

本文目的

使用反射在SpringBoot中对多个校验接口进行统一操作

反射

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

使用场景

项目那个有多个校验接口:比如身份证校验,手机号校验等,如果每个都对该次校验写一个校验方法,如果后期又出现其他组合的校验,最后会很繁琐,代码冗余,难以维护。那么这里使用反射对每个校验方法进行统一的操作,根据请求操作来判断使用那几个组合的校验方法。后期如果有新的校验添加起来也就很方便,容易维护。

实现代码

服务层校验类

public interface BlackValidateService {
    /**
     * @Description: 根据手机号判断是否在黑名单中
     * @param phone
     * @return com.p4.risk.entity.RiskRetCode
     * @author Surpass
     * @date 2020/12/2 13:56
     */
    RiskRetCode getPhone(String phone);

    /**
     * @Description: 根据身份证号判断是否在黑名单中
     * @param idCardNum
     * @return com.p4.risk.entity.RiskRetCode
     * @author Surpass
     * @date 2020/12/2 13:56
     */
    RiskRetCode getIdCardNum(String idCardNum);

    /**
     * @Description: 根据终端号判断是否在黑名单中
     * @param termNo
     * @return com.p4.risk.entity.RiskRetCode
     * @author Surpass
     * @date 2020/12/2 13:56
     */
    RiskRetCode getTermNo(String termNo);

    /**
     * @Description: 根据银行卡号判断是否在黑名单中
     * @param cardNum
     * @return com.p4.risk.entity.RiskRetCode
     * @author Surpass
     * @date 2020/12/2 13:57
     */
    RiskRetCode getCardNum(String cardNum);

    /**
     * @Description: 根据营业执照号判断是否在黑名单中
     * @param busLicenseNo
     * @return com.p4.risk.entity.RiskRetCode
     * @author Surpass
     * @date 2020/12/2 13:57
     */
    RiskRetCode getBusLicenseNo(String busLicenseNo);

    /**
     * @Description: 根据基站号,小区号判断是否在黑名单中
     * @param stationNo
     * @param cellId
     * @return com.p4.risk.entity.RiskRetCode
     * @author Surpass
     * @date 2020/12/2 13:57
     */
    RiskRetCode getBaseStation(String stationNo, String cellId);
}

说明:返回值类型是一个枚举类,返回键值对数据像00、99之类的,实现类就是校验逻辑了,接口方法统一使用“get+请求参数(首字母大写)”。特殊的是最后一个有两个参数,在控制器中会特殊处理,后面接着看。

反射实现控制器

@Slf4j
@RestController
@RequestMapping("/mposDataValidate")
public class MposDataValidateController {

    /**
     * mpos黑名单校验方法
     */
    @Autowired
    private BlackValidateService validate;

    private Gson gson = new Gson();

    /**
     * @Description: 利用反射将黑名单方法和参数进行绑定,根据参数key不同来查询不同的黑名单
     * @param param 需要校验的参数:idCardNum,termNo,cardNum,busLicenseNo,stationNo,cellId,phone
     * @return java.util.Map<java.lang.String , java.lang.Object>
     * @author Surpass
     * @date 2020/12/2 13:22
     */
    @RequestMapping("/dataValidator")
    public Map<String,Object> dataValidator(@RequestBody Map<String,Object> param){
        log.info("mpos外放接口调用,校验黑名单传入参数:"+gson.toJson(param));
        Map<String, Object> resultMap = new HashMap<>(2);
        if (param.size() == 0){
            resultMap.put("rspCode","99");
            resultMap.put("rspMsg","接口数据参数为空");
            log.info("接口数据参数为空");
            return resultMap;
        }
        try {
            //基站号参数key
            String stationNo = "stationNo";
            //小区号参数key
            String cellId = "cellId";
            //基站黑名单方法名
            String baseStationMethodName = "getBaseStation";
            //基站号参数value
            String stationNoVal = null;
            //小区号参数value
            String cellIdVal = null;
            RiskRetCode result = null;
            //获得接口校验的class类对象
            Class<BlackValidateService> cls = BlackValidateService.class;
            //遍历参数
            for (Map.Entry<String, Object> entry : param.entrySet()) {
                String key = entry.getKey();
                String value = (String) entry.getValue();
                if (StringUtils.isBlank(value)){
                    continue;
                }
                //基站信息特殊处理
                if ((stationNo).equals(key)){
                    stationNoVal = value;
                    continue;
                }
                if ((cellId).equals(key)){
                    cellIdVal = value;
                    continue;
                }
                //根据参数key获取方法名   getPhone...
                String methodsName = "get"+key.substring(0,1).toUpperCase()+key.substring(1);
                //根据方法名和方法参数确定某一个方法
                Method method = cls.getMethod(methodsName, String.class);
                //执行,对方法进行访问赋值
                result = (RiskRetCode)method.invoke(validate, value);

                if (Objects.equals(result.getValue(), RiskRetCode.R00.getValue())){
                    //校验通过,进行下一个  00通过
                    resultMap.put("rspCode",RiskRetCode.R00.getValue());
                    resultMap.put("rspMsg",result.getDesc());
                    continue;
                }else {
                    //在黑名单中,直接返回    99不通过
                    resultMap.put("rspCode",RiskRetCode.R99.getValue());
                    resultMap.put("rspMsg",result.getDesc());
                    return resultMap;
                }
            }
            //基站需要基站号和小区号
            if (StringUtils.isNotEmpty(stationNoVal) && StringUtils.isNotEmpty(cellIdVal)){
                //根据方法名和方法参数确定某一个方法
                Method method = cls.getMethod(baseStationMethodName, String.class, String.class);
                //执行,对方法进行访问赋值
                result = (RiskRetCode)method.invoke(validate, stationNoVal,cellIdVal);
            }
            if (Objects.equals(result.getValue(), RiskRetCode.R00.getValue())){
                resultMap.put("rspCode",RiskRetCode.R00.getValue());
                resultMap.put("rspMsg",result.getDesc());
            }else {
                resultMap.put("rspCode",RiskRetCode.R99.getValue());
                resultMap.put("rspMsg",result.getDesc());
                return resultMap;
            }
        }catch (Exception e){
            log.error("mpos外放接口黑名单校验异常",e);
            resultMap.put("rspCode",RiskRetCode.R99.getValue());
            resultMap.put("rspMsg","mpos外放接口黑名单校验异常");
            return resultMap;
        }
        if (resultMap.size() == 0){
            resultMap.put("rspCode", RiskRetCode.R99.getValue());
            resultMap.put("rspMsg", "本次请求没有过任何黑名单接口");
        }
        log.info("mpos外放接口调用,校验黑名单返回参数:"+gson.toJson(resultMap));
        return resultMap;
    }

}

说明:每一个接口校验都会通过参数来判断,特别的基站则需要基站小区两个都存在才会去校验,那么只需要单独判断一下就可以。代码注释还是比较详细的。

尾言

其实当时博主是没有想到使用反射来做的,当收到任务时只想到了怎么if()if()的,哈哈哈,还是大佬告诉我,怎么轻巧,怎么统一,才想到能够这个样子做的,觉得眼光短浅,只注重了眼前,所以接到任务还是需要多思考思考,多回顾回顾,这样子才能成长,一起加油吧!

推荐阅读更多精彩内容