关于业务中未冗余字段的其他表的字段进行映射

  在我所做的业务中,写代码的时候基础的增删改查方法已经封装好,做单表查询是已经不需要写sql脚本。

  所以经常遇到一个问题。假设数据库中有表Table,主键为id,有字段anyName。

  在另一张表Ori表中的tableId字段存了Table表的主键id,现前端需要展示anyName,则需要写一个连表的sql去查出anyName。

  所以做了一个字段映射的工具(该工具只是为了加快开发进度,对性能有要求的情况下不推荐使用)

  

  

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PropertiesMap {
    /**
     * 对应基础数据中具体的类
     * <p>基础数据来自{@link com.linsionxm.wms.utils.BasicObjName} 的全局常量
   * EntityBase中有字段存了表名,所以限制传入的类需要是他的子类,可以根据实际情况调整
*/ Class<? extends EntityBase> objClass() default VoidEntity.class; /** * 对应系统代码中具体的代码 * <p>系统代码来自{@link com.linsionxm.wms.basicdata.entitymodel.enums.CustDefCodeEnum} */ CustDefCodeEnum custCode() default CustDefCodeEnum.DEFAULT; /** * 对应的实体中基础数据id或系统代码 */ String keyName(); /** * 在使用基础数据做字段映射是可指定绑定对应的key,默认使用基础数据的id */ String keyField() default "id"; /** * 在使用基础数据做字段映射是可指定绑定对应的value,默认使用基础数据的name */ String keyValue() default "name"; /** * 取值类型,来自{@link S17BeanUtil}的全局常量 * <p>当取值为{@link S17BeanUtil#BASIC_OBJ_NAME}时,与{@link PropertiesMap#objClass()}配合使用, * 当取值为{@link S17BeanUtil#CUST_DEF_CODE}是,与{@link PropertiesMap#custCode()}配合使用 */ String type() default S17BeanUtil.BASIC_OBJ_NAME; }
@Component
public class S17BeanUtil {
    /**
     * <p>根据{@link PropertiesMap}配置的字段映射信息对实体中的为冗余字段进行相应的字段映射</p>
     * 
     * <p>如果{@link PropertiesMap#keyField()} 和 {@link PropertiesMap#keyValue()}没有进行配置,则默认使用“id” 和 “name”,
     * 这两个属性对应的是{@link PropertiesMap#objClass()}实体对应的数据库字段,如果字段无法匹配将会抛出一个sql异常。
     * 通过配置的这两个属性,拼接一条查询{@link PropertiesMap#objClass()}实体对应的表的sql,最终结果拼接成一个
     * {keyFiled,keyValue}对应值的Map。</p>
     * 
     * <p>{@link PropertiesMap#keyName()}属性对应的是原始集合R中的字段,在做字段映射时通过改值去上文提到的map中检索到对应的value</p>
     * 
     * <p>再举例之前,我们先定义一些我们用得到的对象</p>
     * <pre>{@code 
     *      class OriEntity {
     *          //假定有一张表为table,该字段对应其主键id
     *          //且该表中有一字段为anyName
     *          private String tableId;
     *          
     *          //other field ...
     *          //getter and setter ...
     *      }
     *      
     *      
     *      //table表中对用的数据
     *      {
     *          "id":"1",
     *          "anyName":"name1"
     *      },
     *      {
     *          "id":"2",
     *          "anyName":"name2"
     *      },
     *      //... 以此类推
     *      
     *      
    *      //现定义最终结果的映射对象
     *      class OriEntityVO extends OriEntity{
     *          @PropertiesMap(objClass = Table.class,
     *              keyName = 'tableId',
     *              keyField = 'id',
     *              keyValue = 'anyName'
     *          )
     *          private String anyName;
     *          
     *          //other field ...
     *          //getter and setter ...
     *      }
     *      
     *      
     *      {
     *          OriEntity oe1 = new OriEntity().setTableId("1");
     *          OriEntity oe2 = new OriEntity().setTableId("2");
     *          List<OriEntity> oriList = new ArrayList<>();
     *          List<OriEntityVO> resList = copyPropertiesAndFillingProperties(oriList, OriEntityVO.class);
     *          /*最后可得到OriEntityVO集合为
     *          [
     *              {
     *                  "tableId":"1",
     *                  "anyName":"name1"
     *              },
     *              {
     *                  "tableId":"2",
     *                  "anyName":"name2"
     *              }
     *          ] *\/
     *          
     *      }
     * }</pre>
     * 
     *<pre></pre>
     * @param resultList 需要进行字段映射的初始集合
     * @param voClass 最终结果返回的集合类型
     * @param <R> 原始类型
     * @param <V> 最终类型
     * @return 返回一个映射后的 V 类型的集合
     * @throws Exception
     */
    public static <R, V>
    List<V> copyPropertiesAndFillingProperties(List<R> resultList, Class<V> voClass) throws Exception {
        List<V> voList = new ArrayList<>();
        Field[] fields = voClass.getDeclaredFields();
        Map<Class<?> ,Map<String,String>> allMap = new HashMap<>();
        for (R result : resultList) {
            V vo = voClass.newInstance();
            BeanUtils.copyProperties(result, vo);
            for (Field field : fields) {
                if (field.isAnnotationPresent(PropertiesMap.class)) {
                    PropertiesMap propertiesMap = field.getAnnotation(PropertiesMap.class);
                    String keyName = propertiesMap.keyName();
                    String kfStr = propertiesMap.keyField();
                    String kvStr = propertiesMap.keyValue();
                    Field keyField = getField(voClass, keyName);
                    keyField.setAccessible(true);
                    field.setAccessible(true);
                    Class<? extends EntityBase> objClass = propertiesMap.objClass();
                    List<String> keyList = resultList.stream()
                            .map(i -> {
                                try {
                                    Field rField = i.getClass().getDeclaredField(keyName);
                                    rField.setAccessible(true);
                                    return String.valueOf(rField.get(i));
                                } catch (NoSuchFieldException | IllegalAccessException e) {
                                    return "";
                                }
                            }).distinct()
                            .collect(Collectors.toList());
                    Map<String, String> nameMap = new HashMap<>();
                    if (!VoidEntity.class.getName().equals(objClass.getName())) {
                        Map<String, String> map = allMap.getOrDefault(objClass, null);
                        if (null == map) {
                            map = BasicObjName.getMap(objClass, kfStr, kvStr, keyList);
                            allMap.put(objClass, map);
                        }
                        nameMap = map;
                    }
                    String keyValue = Objects.toString(keyField.get(vo), "");
                    if (BASIC_OBJ_NAME.equals(propertiesMap.type())) {
                        if (!VoidEntity.class.getName().equals(objClass.getName())) {
                            field.set(vo, nameMap.get(keyValue));
                        }
                    } else if (CUST_DEF_CODE.equals(propertiesMap.type())) {
                        CustDefCodeEnum codeEnum = propertiesMap.custCode();
                        field.set(vo, staticCustDefCodeService.getNameByField(codeEnum.getCode(), keyValue));
                    }
                }
            }
            voList.add(vo);
        }
        return voList;
    }
}
public static <R extends EntityBase> Map<String, String> getMap(Class<R> clazz, String keyField, String valueField, List<String> keyList) {
        try {
            String tableName = clazz.newInstance().getS17_TableName();
            String sql = "select " +
                    keyField + " as `key`," +
                    valueField + " as value " +
                    "from " + tableName;
            if (!CollectionUtils.isEmpty(keyList)) {
                List<String> param = new ArrayList<>();
                keyList.forEach(key -> {
                    param.add("'" + key + "'");
                });
                sql += " where " + keyField + " in (" + String.join(",", param) + ")";
            }
            List<KeyAndValue> list = D_S17VOSqlMapper.selectList(staticDaoService.mySqlSession(), sql, KeyAndValue.class);
            return list.stream()
                    .collect(Collectors.toMap(
                            KeyAndValue::getKey,
                            KeyAndValue::getValue,
                            (oldV, newV) -> newV
                    ));
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
            return new HashMap<>();
        }
    }
@Data
public class KeyAndValue {
    private String key;
    private String value;
}

 

posted @ 2023-03-20 16:25  FFFa_aNNN  阅读(40)  评论(0)    收藏  举报