XxlJobAnalyticParamUtil(乐乐独记)

1、业务背景

这篇博客主要是我们公司在用针一个轻量级分布式任务调度平台,名叫xxlJob,也可以简单理解为一种定时任务,在这个平台中,可以传递一个字符串参数给具体的业务代码,由于传递参数的方式大家各不相同,而且太乱,所以我就定义了这一套规范,类似于web项目中get方式传参的模式,传一个字符串给后端,后端定义好一个模型,用我下面的工具类可以直接转换成相应的模型并赋值。使得参数更加清晰明了,代码如下:

2、代码

2.1、引用pom文件

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.16</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.47</version>
</dependency>

2.2、工具类

package xxlJob;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * xxlJob 解析参数类
 * 目前支持的参数形式如下所示,以 & 分隔参数个数:
 * stringType=ale
 * &integerType=1000
 * &stringListType=233021258120003999,333020570110869001,141092358120000001
 * &bigDecimalType=500.6
 * &mapType={a:111,b:222}
 *目前支持的数据类型:
     * String dealNum;
     * Integer pageSize;
     * List<String> shopIdList;
     * BigDecimal amount;
     * Map<String, String> stringMap;
 * xxlJob按照上面字符串传入,模型按照后面写就可以映射的上,主要是参数名得对应上
 * @author k10156 杜佳乐
 * @date 20220803
 */
@Slf4j
public class XxlJobAnalyticParamUtil {
    /**
     * 字段分隔符
     */
    private static final String FIELDS_SPLIT = "&";

    /**
     * 字段的名与value分隔符
     */
    private static final String FIELD_NAME_AND_VALUE_SPLIT = "=";

    /**
     * List 元素之间的分隔符
     */
    private static final String LIST_SPLIT = ",";

    /**
     * 支持映射的字段数据类型
     */
    private static final Class[] FIELD_TYPE_ARRAY = {
            String.class,
            Integer.class,
            List.class,
            BigDecimal.class,
            Map.class
    };

    /**
     * 外部提供的方法
     *
     * @param taskName     任务名称
     * @param param        传入的参数字符串
     * @param resultObject 将传入的参数字符串整合成模型返回
     * @return 返回整合的模型
     */
    public static Object execute(String taskName, String param, Object resultObject) {
        log.info("execute方法开始:");
        // 执行真正的方法
        return analyticParameter(taskName, param, resultObject);
    }

    /** 
     * 解析参数主方法 
     * @param taskName          任务名称 
     * @param param             传入的参数字符串 
     * @param resultObject      将传入的参数字符串整合成模型返回 
     * @return                  返回整合的模型 
     */
     private static Object analyticParameter(String taskName, String param, Object resultObject) { 
        log.info("analyticParameter方法开始:");
        if (null == param || "".equals(param) || null == resultObject){
            return resultObject; 
        }
        // 获取到返回模型的所有字段列表(所有信息) 
        Field[] fields = resultObject.getClass().getDeclaredFields(); 
        if (fields.length == 0){ 
            return resultObject; 
        } 
        List<String> fieldNameList = new ArrayList<String> (fields.length * 2);
        // 将所有的字段名称全部放进去 
        for ( int i = 0; i < fields.length; i++){ 
            fieldNameList.add(fields[i].getName()); 
        } 
        // 取出传入的字段名称 
        String[] parameterList = param.split(FIELDS_SPLIT); 
        for ( int i = 0; i < parameterList.length; i++){ 
            resultObject = matchParameter(taskName, parameterList[i], fieldNameList, resultObject); 
        } 
        return resultObject; 
    }

    /** 
     * 匹配单个参数并赋值给模型 
     * @param taskName              任务名称 
     * @param requestParamValue     单个参数的请求值  dealNum:100 
     * @param fieldNameList         传入模型的字段属性列表 
     * @param resultObject          需要继续注入属性值的返回结果模型 
     * @return      将增加了新的参数值注入的结果模型返回 
     */ 
    private static Object matchParameter(String taskName, String requestParamValue, 
                                              List<String> fieldNameList, Object resultObject) 

    { 
        log.info("matchParameter方法开始:"); 
        // 定义一个返回结果模型临时变量,不能对传入的参数直接修改 
        Object resultObjectTemp = resultObject; 
        if (null == requestParamValue || "".equals(requestParamValue)){ 
            return resultObjectTemp; 
        } 
        // 不等于空时,分隔 
        String[] singleParamSplit = requestParamValue.split(FIELD_NAME_AND_VALUE_SPLIT); 
        if (singleParamSplit.length != 2){ 
            log.info("[{}]分隔参数[{}]时出现异常,请检查参数。", taskName, requestParamValue); 
            return resultObjectTemp; 
        }// 校验名称是否相等,如果不相等,则返回 
        String currentParamName = singleParamSplit[0]; 
        if (fieldNameList.contains(currentParamName)) { 
            String fillContent = singleParamSplit[1]; 
            // 匹配方法并赋值填充内容 
            matchMethodAndFillContent(resultObjectTemp, currentParamName, fillContent, taskName, 
                                                    requestParamValue); 
        }else{ 
            log.info("[{}]赋值参数[{}]时名称不存在,请检查参数。", taskName, requestParamValue); 
        } 
        // 返回组装好的模型 
        return resultObjectTemp; 
    }

    /** 
     * 匹配方法并赋值填充内容 
     * @param resultObjectTemp      需要返回映射的对象 
     * @param currentParamName      当前需要映射的参数名称 
     * @param fillContent           当前需要映射的参数的填充内容 
     * @param taskName              当前执行xxlJob任务的名称 
     * @param requestParamValue     当前需要映射匹配的请求原始内容,如:dealNum:100 
     */ 
    private static void matchMethodAndFillContent(Object resultObjectTemp, String currentParamName, String fillContent, 
                                                       String taskName, String requestParamValue) { 
        log.info("matchMethodAndFillContent方法开始:"); 
        // set 方法临时变量 
        Method setMethod = null; 
        // 是否赋值上 
        boolean matchSuccessFlag = false; 
        for ( int index = 0; index < FIELD_TYPE_ARRAY.length ; index++){ 
            try { 
                setMethod = resultObjectTemp.getClass().getMethod("set"  + 
                                // 对首字母大写 
                                currentParamName.substring(0, 1).toUpperCase() + currentParamName.substring(1), 
                        // 方法的参数类型 
                        FIELD_TYPE_ARRAY[index]);
                // 若匹配上,则会走下面这行反射执行 set 方法
                invokeExecute(setMethod, fillContent, resultObjectTemp, FIELD_TYPE_ARRAY[index]); 
                matchSuccessFlag = true; 
                break; 
            } catch (Exception e){
                log.debug("errorStack:", e);
                // 进行下一个类型的匹配,这里不需要打印日志
            } 
        } 
        if (matchSuccessFlag) { 
            log.info("[{}]赋值参数[{}]时完成。", taskName, requestParamValue); 
        }else { 
            log.info("[{}]赋值参数[{}]失败。", taskName, requestParamValue); 
        } 
    }

    /** 
     * 根据不同的类型,执行不同的 invoke 设置数据调用方法 
     * @param setMethod         set的方法代理对象 
     * @param fillContent       需要填充的参数内容 
     * @param resultObjectTemp  需要返回的对象 
     * @param clazz             不同的参数类型 
     * @throws InvocationTargetException    异常1 
     * @throws IllegalAccessException       异常2 
     */ 
    private static void invokeExecute(Method setMethod, String fillContent, Object resultObjectTemp, Class clazz) 
                                        throws InvocationTargetException, IllegalAccessException { 
        log.info("invokeExecute方法开始:"); 
        if (clazz == String.class){ 
            setMethod.invoke(resultObjectTemp, fillContent); 
        } 
        else if (clazz == Integer.class) { 
            setMethod.invoke(resultObjectTemp, Integer.valueOf(fillContent)); 
        }
        else if (clazz == List.class){
            setMethod.invoke(resultObjectTemp, Arrays.asList(fillContent.split(LIST_SPLIT))); 
        } 
        else if (clazz == BigDecimal.class){ 
            setMethod.invoke(resultObjectTemp,  new BigDecimal(fillContent)); 
        } 
        else if (clazz == Map.class){
            setMethod.invoke(resultObjectTemp, JSON.parseObject(fillContent, Map.class));
        } 
        else { 
            log.info("不支持该类型的映射!"); 
        } 
    }
}

2.3、测试类

测试模型

@Data
public class TestModel {

    private String stringType;

    private String integerType;

    private List<String> stringListType;

    private BigDecimal bigDecimalType;

    private Map<String, String> mapType;

}

单元测试

String param = "stringType=ale&integerType=1000&stringListType=233021258120003999,333020570110869001,141092358120000001&bigDecimalType=500.6&mapType={a:111,b:222}";
TestModel list = (TestModel) XxlJobAnalyticParamUtil.execute("", param, new TestModel());
System.out.println(list);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值