轻蜗牛直租平台-common-utils工具类简介

一、背景

我在几家公司工作的过程中发现不同的部门等都会封装一些工具类,比如统一一些异常枚举,统一请求响应,分页工具实体等,因此我在进行业务实战的时候也希望先统一一些api规范和标准,便于快速开发和推广。平时我也会总结一些工具类将之前自己写的或者网上找的工具类放在一起,便于开发新的工具组件和应用到业务系统中。这里专门开一篇文章介绍一下有哪些工具类。

二、工具列表

这里分几个小章节来介绍一些目前有的工具类。

2.1 基于cglib的bean拷贝服务

  1. 功能描述:基于cglib代理中的BeanCopier功能实现entity,dto等对象之间的相互转换
  2. 实现:

接口定义:

package com.coderman.utils.bean;

import net.sf.cglib.beans.BeanCopier;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by  on 2017-10-19.
 *
 * @author: fanchunshuai
 * @version: V1.0
 * @Desc:
 * BeanCopier拷贝速度快,性能瓶颈出现在创建BeanCopier实例的过程中。
 * 所以,把创建过的BeanCopier实例放到缓存中,下次可以直接获取,提升性能
 */
public class CachedBeanCopier {
    private static final Map<String, BeanCopier> BEAN_COPIERS = new HashMap<String, BeanCopier>();

    public static BeanCopier getBeanCopier(Object srcObj, Object destObj) {

        BeanCopier copier = null;

        String key = genKey(srcObj.getClass(),destObj.getClass());

        if (!BEAN_COPIERS.containsKey(key)) {
            copier = BeanCopier.create(srcObj.getClass(), destObj.getClass(), false);
            BEAN_COPIERS.put(key, copier);
        } else {
            copier = BEAN_COPIERS.get(key);
        }

        return copier;
    }

    private static String genKey(Class<?> srcClazz, Class<?> destClazz) {
        return srcClazz.getName() + destClazz.getName();
    }

}

接口实现:

package com.coderman.utils.bean;

import net.sf.cglib.beans.BeanCopier;

import java.util.LinkedList;
import java.util.List;

/**
 * Created by on 2017-10-17.
 *
 * @author: fanchunshuai
 * @version: V1.0
 * @Desc:
 */
public class CglibConvertService implements IConvert {


    @Override
    public <T, K> List<T> copyPropertities(Class<T> clazz, List<K> objList) throws Exception {
        List<T> descList = new LinkedList<T>() ;
        if(objList==null){
            return null;
        }
        for(K k : objList){
            descList.add(copyPropertity(clazz, k));
        }
        return descList;
    }

    @Override
    public <T> T copyPropertity(Class<T> clazz, Object orig) throws Exception {
        T t = clazz.newInstance();
        BeanCopier beanCopier = CachedBeanCopier.getBeanCopier(orig,t);
        beanCopier.copy(orig,t,null);
        return t;
    }
}

辅助类CachedBeanCopier:

package com.coderman.utils.bean;

import net.sf.cglib.beans.BeanCopier;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by  on 2017-10-19.
 *
 * @author: fanchunshuai
 * @version: V1.0
 * @Desc:
 * BeanCopier拷贝速度快,性能瓶颈出现在创建BeanCopier实例的过程中。
 * 所以,把创建过的BeanCopier实例放到缓存中,下次可以直接获取,提升性能
 */
public class CachedBeanCopier {
    private static final Map<String, BeanCopier> BEAN_COPIERS = new HashMap<String, BeanCopier>();

    public static BeanCopier getBeanCopier(Object srcObj, Object destObj) {

        BeanCopier copier = null;

        String key = genKey(srcObj.getClass(),destObj.getClass());

        if (!BEAN_COPIERS.containsKey(key)) {
            copier = BeanCopier.create(srcObj.getClass(), destObj.getClass(), false);
            BEAN_COPIERS.put(key, copier);
        } else {
            copier = BEAN_COPIERS.get(key);
        }

        return copier;
    }

    private static String genKey(Class<?> srcClazz, Class<?> destClazz) {
        return srcClazz.getName() + destClazz.getName();
    }

}

2.2 基于javassist的类元数据查找服务

  1. 功能描述:基于javassist工具包实现JVM中的class元数据信息查找,加载等,经常用于反射,类加载,读取指定包下的类元数据信息等。这个工具类网上也有,这里集成一下。
  2. 实现:
package com.coderman.utils.clazz;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.JarURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Stream;

/**
 * Created 2018-10-16.
 *
 * @author: fanchunshuai
 * @version: V1.0
 * @Desc:      class加载工具类
 */
public class ClassUtils {
    /** jar中的文件路径分隔符 */
    private static final char SLASH_CHAR = '/';
    /** 包名分隔符 */
    private static final char DOT_CHAR = '.';

    /**
     * 在当前项目中寻找指定包下的所有类
     *
     * @param packageName 用'.'分隔的包名
     * @param recursive 是否递归搜索
     * @return 该包名下的所有类
     */
    public static List<Class<?>> getClass(String packageName, boolean recursive) {
        List<Class<?>> classList = new ArrayList<>();
        try {
            //获取当前线程的类装载器中相应包名对应的资源
            Enumeration<URL> iterator = Thread.currentThread().getContextClassLoader().getResources(packageName.replace(DOT_CHAR, File.separatorChar));
            while (iterator.hasMoreElements()) {
                URL url = iterator.nextElement();
                String protocol = url.getProtocol();
                List<Class<?>> childClassList = Collections.emptyList();
                switch (protocol) {
                    case "file":
                        childClassList = getClassInFile(url, packageName, recursive);
                        break;
                    case "jar":
                        childClassList = getClassInJar(url, packageName, recursive);
                        break;
                    default:
                        //在某些WEB服务器中运行WAR包时,它不会像TOMCAT一样将WAR包解压为目录的,如JBOSS7,它是使用了一种叫VFS的协议
                        System.out.println("unknown protocol " + protocol);
                        break;
                }
                classList.addAll(childClassList);
            }
            return classList;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    /**
     * 在给定的文件或文件夹中寻找指定包下的所有类
     *
     * @param filePath 包的路径
     * @param packageName 用'.'分隔的包名
     * @param recursive 是否递归搜索
     * @return 该包名下的所有类
     */
    public static List<Class<?>> getClassInFile(String filePath, String packageName, boolean recursive) {
        Path path = Paths.get(filePath);
        return getClassInFile(path, packageName, recursive);
    }

    /**
     * 在给定的文件或文件夹中寻找指定包下的所有类
     *
     * @param url 包的统一资源定位符
     * @param packageName 用'.'分隔的包名
     * @param recursive 是否递归搜索
     * @return 该包名下的所有类
     */
    public static List<Class<?>> getClassInFile(URL url, String packageName, boolean recursive) {
        try {
            Path path = Paths.get(url.toURI());
            return getClassInFile(path, packageName, recursive);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    /**
     * 在给定的文件或文件夹中寻找指定包下的所有类
     *
     * @param path 包的路径
     * @param packageName 用'.'分隔的包名
     * @param recursive 是否递归搜索
     * @return 该包名下的所有类
     */
    public static List<Class<?>> getClassInFile(Path path, String packageName, boolean recursive) {
        if (!Files.exists(path)) {
            return Collections.emptyList();
        }
        List<Class<?>> classList = new ArrayList<Class<?>>();
        if (Files.isDirectory(path)) {
            if (!recursive) {
                return Collections.emptyList();
            }
            try {
                //获取目录下的所有文件
                Stream<Path> stream = Files.list(path);
                Iterator<Path> iterator = stream.iterator();
                while (iterator.hasNext()) {
                    classList.addAll(getClassInFile(iterator.next(), packageName, recursive));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            try {
                //由于传入的文件可能是相对路径, 这里要拿到文件的实际路径, 如果不存在则报IOException
                path = path.toRealPath();
                String pathStr = path.toString();
                //这里拿到的一般的"aa:\bb\...\cc.class"格式的文件名, 要去除末尾的类型后缀(.class)
                int lastDotIndex = pathStr.lastIndexOf(DOT_CHAR);
                //Class.forName只允许使用用'.'分隔的类名的形式
                String className = pathStr.replace(File.separatorChar, DOT_CHAR);
                //获取包名的起始位置
                int beginIndex = className.indexOf(packageName);
                if (beginIndex == -1) {
                    return Collections.emptyList();
                }
                className = lastDotIndex == -1 ? className.substring(beginIndex) : className.substring(beginIndex, lastDotIndex);
                classList.add(Class.forName(className));
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return classList;
    }

    /**
     * 在给定的jar包中寻找指定包下的所有类
     *
     * @param filePath 包的路径
     * @param packageName 用'.'分隔的包名
     * @param recursive 是否递归搜索
     * @return 该包名下的所有类
     */
    public static List<Class<?>> getClassInJar(String filePath, String packageName, boolean recursive) {
        try {
            JarFile jar = new JarFile(filePath);
            return getClassInJar(jar, packageName, recursive);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    /**
     * 在给定的jar包中寻找指定包下的所有类
     *
     * @param url jar包的统一资源定位符
     * @param packageName 用'.'分隔的包名
     * @param recursive 是否递归搜索
     * @return 该包名下的所有类
     */
    public static List<Class<?>> getClassInJar(URL url, String packageName, boolean recursive) {
        try {
            JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
            return getClassInJar(jar, packageName, recursive);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    /**
     * 在给定的jar包中寻找指定包下的所有类
     *
     * @param jar jar对象
     * @param packageName 用'.'分隔的包名
     * @param recursive 是否递归搜索
     * @return 该包名下的所有类
     */
    public static List<Class<?>> getClassInJar(JarFile jar, String packageName, boolean recursive) {
        List<Class<?>> classList = new ArrayList<>();
        //该迭代器会递归得到该jar底下所有的目录和文件
        Enumeration<JarEntry> iterator = jar.entries();
        while (iterator.hasMoreElements()) {
            //这里拿到的一般的"aa/bb/.../cc.class"格式的Entry或 "包路径"
            JarEntry jarEntry = iterator.nextElement();
            if (!jarEntry.isDirectory()) {
                String name = jarEntry.getName();
                //对于拿到的文件,要去除末尾的.class
                int lastDotClassIndex = name.lastIndexOf(".class");
                if(lastDotClassIndex != -1) {
                    int lastSlashIndex = name.lastIndexOf(SLASH_CHAR);
                    name = name.replace(SLASH_CHAR, DOT_CHAR);
                    if(name.startsWith(packageName)) {
                        if(recursive || packageName.length() == lastSlashIndex) {
                            String className = name.substring(0, lastDotClassIndex);
                            try {
                                classList.add(Class.forName(className));
                            } catch (ClassNotFoundException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
        return classList;
    }


    public static Map<String,String> getParameterNames(Class clazz){
        Map<String,String> paramMap = new HashMap<>();
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass cc = pool.get(clazz.getName());

            Method [] methods = clazz.getDeclaredMethods();
            for (Method method : methods){

                CtMethod cm = cc.getDeclaredMethod(method.getName());
                // 使用javaassist的反射方法获取方法的参数名
                MethodInfo methodInfo = cm.getMethodInfo();
                if(methodInfo.getName().contains("lambda") && methodInfo.getName().contains("$")){
                    continue;
                }


                CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
                LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
                if (attr == null) {
                    paramMap.put(method.getName(),"");
                }
                String[] paramNames = new String[cm.getParameterTypes().length];
                int paramLength;
                if(paramNames.length > 10){
                    paramLength = 10;
                }else {
                    paramLength = paramNames.length;
                }

                int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
                for (int i = 0; i < paramLength; i++) {
                    paramNames[i] = attr.variableName(i + pos);
                }

                paramMap.put(method.getName(), StringUtils.join(paramNames,","));
            }
        } catch (NotFoundException e) {
            e.printStackTrace();
        }

        return paramMap;
    }
    /**
     * 读取class
     *
     * @param classFilePath
     * @return
     */
    public static byte[] readClassBytes(String  classFilePath) {
        byte[] raw = null;
        InputStream stream = null;
        try {
            File file = new File(classFilePath);
            stream = new FileInputStream(file);
            raw = new byte[(int) file.length()];
            stream.read(raw);
        } catch (Exception e) {

        } finally {
            try {
                stream.close();
            } catch (Exception e) {
            }
        }
        return raw;
    }

}

2.3 DateUtils日期工具类

  1. 功能描述:简单封装的日期处理转换工具类,目前提供的方法不是很多,后续会继续加入
  2. 实现:
package com.coderman.utils.date;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Author fanchunshuai
 * @Date 2019/10/11 15
 * @Description:
 */
public class DateUtils {
    /**
     * date类型进行格式化输出(返回类型:String)
     * @param date
     * @return
     */
    public static String dateFormat(Date date) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = formatter.format(date);
        return dateString;
    }


    /**
     * date类型进行格式化输出(返回类型:String)
     * @param date
     * @return
     */
    public static String dateFormat(Date date,String formatForm) {
        SimpleDateFormat formatter = new SimpleDateFormat(formatForm);
        String dateString = formatter.format(date);
        return dateString;
    }

    /**
     * 将"2015-08-31 21:08:06"型字符串转化为Date
     * @param str
     * @return
     * @throws ParseException
     */
    public static Date StringToDate(String str) throws ParseException {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = formatter.parse(str);
        return date;
    }

    /**
     * 将"2015-08-31 21:08:06"型字符串转化为Date
     * @param str
     * @return
     * @throws ParseException
     */
    public static Date StringToDate(String str,String formatForm) throws ParseException {
        SimpleDateFormat formatter = new SimpleDateFormat(formatForm);
        Date date = formatter.parse(str);
        return date;
    }


    /**
     * 将当前时间戳转化为Date
     * @param str
     * @return
     * @throws ParseException
     */
    public static Date LongToDate(long str) throws ParseException{
        return new Date(str);
    }

    /**
     * 将当前时间戳转化为Date,然后转换为yyyy-MM-dd等格式
     * @param str
     * @return
     * @throws ParseException
     */
    public static String  LongToDateStr(long str,String formatForm) throws ParseException{
        return dateFormat(new Date(str),formatForm);
    }

    /**
     * 两个时间之间的天数
     * @param date1
     * @param date2
     * @return
     */
    public static long getDays(String date1, String date2) {
        if (date1 == null || date1.equals("")) {
            return 0;
        }
        if (date2 == null || date2.equals("")) {
            return 0;
        }
        // 转换为标准时间
        SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");
        java.util.Date date = null;
        java.util.Date mydate = null;
        try {
            date = myFormatter.parse(date1);
            mydate = myFormatter.parse(date2);
        } catch (Exception e) {
        }
        long day = (date.getTime() - mydate.getTime()) / (24 * 60 * 60 * 1000);
        return day;
    }

}

2.4 EnumUtils枚举工具类

  1. 功能描述:借助于ClassUtils读取项目工程下的枚举包,将枚举类中定义的枚举数据读取出来,以map<k,v>的形式返回并供上层使用。
  2. 实现:
package com.coderman.utils.enums;


import com.coderman.utils.clazz.ClassUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author fanchunshuai
 * @Date 2019/2/21 09
 * @Description: 扫描当前项目工程包下所有枚举类生成
 * Map<key,value>和Map<value,key>格式的数据结构
 *
 */
public class EnumUtils {

    /**
     * 获取枚举类中的数据以map->k,v的形式返回
     * map.key:是枚举类名
     * map.v.key:是枚举类中属性的第一个值
     * map.v.value:是枚举类中属性的第2->n个值,多个值使用,分隔
     * 如果枚举只有一个属性,则map.v.key = map.v.value
     * 默认采用递归的方式获取packagePath下所有枚举类,
     * 如果packagePath下存在类名相同的枚举类则会发生覆盖的情况。
     * @param packagePath  扫描枚举类的包路径
     * @return 如果出现异常则返回null
     */
    public static Map<String, Map<String,String>> getServiceEnumMap(String packagePath){
        List<Class<?>> classEnumsList =  ClassUtils.getClass(packagePath,true);
        Map<String, Map<String,String>> enumMap = new HashMap<>();
        try {
            for (Class<?> clazz : classEnumsList){
                if(clazz.isEnum()){
                    List<String> fieldList = getEnumFieldList(clazz);
                    Map<String,Method> methodMap = getEnumMethodList(fieldList,clazz);

                    Object[] objects = clazz.getEnumConstants();
                    Map<String,String> enumDataMap = new HashMap<>();
                    for (Object obj : objects){
                        // 3.调用对应方法,得到枚举常量中字段的值
                        List<String> valueList = new ArrayList<>();
                        methodMap.forEach((k,v)->{
                            try {
                                String value = v.invoke(obj).toString();
                                valueList.add(value);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        });
                        String value = "";
                        if(valueList.size() > 2){
                            StringBuilder builder = new StringBuilder();
                            for (int i = 1;i < valueList.size();i ++){
                                builder.append(valueList.get(i)+",");
                            }
                            value = builder.substring(0,builder.length() - 1);
                        }
                        else if(valueList.size() == 2){
                            value = valueList.get(1);
                        }
                        else if(valueList.size() == 1){
                            value = valueList.get(0);
                        }
                        enumDataMap.put(valueList.get(0),value);
                    }
                    enumMap.put(clazz.getSimpleName(),enumDataMap);
                }
            }
            return enumMap;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取枚举类中的数据以map->k,v的形式返回
     * map.key:是枚举类名
     * map.v.key:是枚举类中属性的最后一个值
     * map.v.value:是枚举类中属性的第1->(n-1)个值,多个值使用,分隔
     * 如果枚举只有一个属性,则map.v.key = map.v.value
     * 默认采用递归的方式获取packagePath下所有枚举类,
     * 如果packagePath下存在类名相同的枚举类则会发生覆盖的情况。
     * @param packagePath  扫描枚举类的路径
     * @return 如果出现异常则返回null
     *
     * 与上面的工具方法是相辅相成的
     */
    public static Map<String, Map<String,String>> getServiceConvertEnumMap(String packagePath){
        List<Class<?>> classEnumsList =  ClassUtils.getClass(packagePath,true);
        Map<String, Map<String,String>> convertEnumMap = new HashMap<>();
        try {
            for (Class<?> clazz : classEnumsList){
                if(clazz.isEnum()){
                    List<String> fieldList = getEnumFieldList(clazz);
                    Map<String,Method> methodMap = getEnumMethodList(fieldList,clazz);

                    Object[] objects = clazz.getEnumConstants();
                    Map<String,String> convertenumDataMap = new HashMap<>();
                    for (Object obj : objects){
                        // 3.调用对应方法,得到枚举常量中字段的值
                        List<String> valueList = new ArrayList<>();
                        methodMap.forEach((k,v)->{
                            try {
                                String value = v.invoke(obj).toString();
                                valueList.add(value);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        });
                        String value = "";
                        if(valueList.size() > 2){
                            StringBuilder builder = new StringBuilder();
                            for (int i = 0;i < valueList.size() - 1;i ++){
                                builder.append(valueList.get(i)+",");
                            }
                            value = builder.substring(0,builder.length() - 1);
                        }
                        else if(valueList.size() == 2){
                            value = valueList.get(0);
                        }
                        else if(valueList.size() == 1){
                            value = valueList.get(0);
                        }
                        convertenumDataMap.put(valueList.get(valueList.size() - 1),value);
                    }
                    convertEnumMap.put(clazz.getSimpleName(),convertenumDataMap);
                }
            }
            return convertEnumMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 根据枚举类动态获取枚举类中的变量
     * @param clazz
     * @return
     */
    private static List<String> getEnumFieldList(Class<?> clazz){
        List<String> enumFieldList = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields){
            if(field.isEnumConstant() == false  && !field.getName().startsWith("$")){
                enumFieldList.add(field.getName());
            }
        }
        return enumFieldList;
    }

    /**
     * 根据枚举类动态获取枚举类中的变量
     * @param fieldNameList
     * @param clazz
     * @return
     */
    private static Map<String, Method> getEnumMethodList(List<String> fieldNameList, Class<?> clazz) throws NoSuchMethodException {
        Map<String,Method>  methodList = new HashMap<>();
        for (String fieldName : fieldNameList){
            String methodName = getGetMethodStr(fieldName);
            Method targetMethod = clazz.getMethod(methodName);
            methodList.put(fieldName,targetMethod);
        }
        return methodList;
    }

    /**
     * 获取get方法
     * @param fieldName
     * @return
     */
    private static String getGetMethodStr(String fieldName){
        return "get"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
    }
}

2.5 KV数据容器类

  1. 功能描述:对普通的k-v类业务数据或者配置数据进行对象封装,类似map<k,v>,这种结构在下拉框中很常见。
  2. 实现:
package com.coderman.utils.kvpair;

import java.util.Objects;

/**
 * description: KVPair <br>
 * date: 2020/7/18 0:29 <br>
 * author: coderman <br>
 * version: 1.0 <br>
 * k-v键值对对象
 */
public class KVPair<K,V> {
    public KVPair(){

    }
    public KVPair(K k,V v){
        this.k = k;
        this.v = v;
    }
    protected K k;
    protected V v;

    public K getK() {
        return k;
    }

    public void setK(K k) {
        this.k = k;
    }

    public V getV() {
        return v;
    }

    public void setV(V v) {
        this.v = v;
    }

    public static <K, V> KVPair<K, V> build(K k, V v) {
        return new KVPair<>(k, v);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o){
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        KVPair<?, ?> kvPair = (KVPair<?, ?>) o;
        return Objects.equals(k, kvPair.k) &&
                Objects.equals(v, kvPair.v);
    }

    @Override
    public int hashCode() {
        return Objects.hash(k, v);
    }
}
  1. kvp结构(这种适用于kv之间有父子关系的场景)
package com.coderman.utils.kvpair;

import java.util.Objects;

/**
 * description: KVParentPair <br>
 * date: 2020/9/6 16:09 <br>
 * author: coderman <br>
 * version: 1.0 <br>
 * 具有父子级关系的三元组
 */
public class KVParentPair<K,V,P> extends KVPair<K,V> {
    private P p;
    public KVParentPair(){}

    public KVParentPair(K k,V v ,P p){
        super(k,v);
        this.p = p;
    }

    public P getP() {
        return p;
    }

    public void setP(P p) {
        this.p = p;
    }

    public static <K, V> KVPair<K, V> build(K k, V v) {
        return new KVPair<>(k, v);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o){
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        KVParentPair<?, ?, ?> kvParentPair = (KVParentPair<?, ?, ?>) o;
        return Objects.equals(kvParentPair.k, super.k) &&
                Objects.equals(kvParentPair.v, super.v) && Objects.equals(kvParentPair.p,this.p);
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.k, super.v,p);
    }
}
  1. 优化

其实对于KVP这种结构算是一种鸡肋,不够抽象,因此可以扩展为三元组对象,或者四元组对象。

2.6 接口返回封装类

  1. 功能描述:封装接口的返回值,包括http接口和service接口,这里将返回场景区分开来,一种是有返回对象的一种是没有的,因此可以从接口声明中看出来,算是一种优点。
  2. 实现:
package com.coderman.utils.response;

/**
 * description: ResultDto <br>
 * date: 2020/7/7 0:03 <br>
 * author: coderman <br>
 * version: 1.0 <br>
 */
public class ResultDto {
    private int  code;
    private String msg;


    public boolean isSuccess(){
        return this.code == ResultDataDto.CodeEnum.SUCCESS.getCode();
    }

    public ResultDto(){}
    public ResultDto(int code,String msg){
        this.code = code;
        this.msg = msg;
    }
    public  ResultDto setErrorCodeMsg(String msg){
        this.code = ResultDataDto.CodeEnum.ERROR.getCode();
        this.msg = msg;
        return  this;
    }

    public static ResultDto returnNullErrorMsg(String msg){
        String newMsg = "调用参数/结果为空" ;
        if(msg != null){
            newMsg = newMsg + msg;
        }
        return new ResultDto(ResultDataDto.CodeEnum.NULL_ERROR.getCode(),newMsg);
    }


    public static ResultDto setParamErrorMsg(String msg){
        String newMsg = "调用参数/结果为空" ;
        if(msg != null){
            newMsg = newMsg + ":" + msg;
        }
        return new ResultDto(ResultDataDto.CodeEnum.PARAM_ERROR.getCode(),newMsg);
    }

    public  ResultDto setInvokeErrorMsg(String msg){
        String newMsg = "调用方法异常" ;
        if(msg != null){
            newMsg = newMsg  + ":" + msg;
        }
        this.code = ResultDataDto.CodeEnum.INVOKE_ERROR.getCode();
        this.msg = newMsg;
        return  this;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
package com.coderman.utils.response;

/**
 * description: ResultDataDto <br>
 * date: 2020/7/7 0:04 <br>
 * author: coderman <br>
 * version: 1.0 <br>
 */
public class ResultDataDto<T> {
    private int  code;
    private String msg;
    private T data;
    public ResultDataDto(){}


    public boolean isSuccess(){
        return this.code == CodeEnum.SUCCESS.getCode();
    }
    public ResultDataDto(int code,String msg){
        this.code = code;
        this.msg = msg;
    }
    public  ResultDataDto<T> setErrorCodeMsg(String msg){
        this.code = CodeEnum.ERROR.getCode();
        this.msg = msg;
        return  this;
    }

    public ResultDataDto<T> setData(T data){
        this.data = data;
        this.code = CodeEnum.SUCCESS.getCode();
        this.msg = "成功";
        return this;
    }

    public static ResultDataDto returnSuccess(){
        return new ResultDataDto(CodeEnum.SUCCESS.getCode(),"成功");
    }

    public static  <T> ResultDataDto<T> returnSuccess(T data){
        ResultDataDto<T> resultDataDto = new ResultDataDto(CodeEnum.SUCCESS.getCode(),"成功");
        return resultDataDto.setData(data);
    }
    public static ResultDataDto returnNullErrorMsg(String msg){
        String newMsg = "调用参数/结果为空" ;
        if(msg != null){
            newMsg = newMsg + msg;
        }
        return new ResultDataDto(CodeEnum.NULL_ERROR.getCode(),newMsg);
    }


    public static ResultDataDto setParamErrorMsg(String msg){
        String newMsg = "调用参数/结果为空" ;
        if(msg != null){
            newMsg = newMsg + ":" + msg;
        }
        return new ResultDataDto(CodeEnum.PARAM_ERROR.getCode(),newMsg);
    }

    public  ResultDataDto<T> setInvokeErrorMsg(String msg){
        String newMsg = "调用方法异常" ;
        if(msg != null){
            newMsg = newMsg  + ":" + msg;
        }
        this.code = CodeEnum.INVOKE_ERROR.getCode();
        this.msg = newMsg;
        return  this;
    }

    enum CodeEnum{
        SUCCESS(0),
        ERROR(-1),
        NULL_ERROR(-2),
        PARAM_ERROR(-3),
        INVOKE_ERROR(-4),
        ;

        int code;
        CodeEnum(int code){this.code = code;}

        public int getCode() {
            return code;
        }
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }
}

三、版本迭代

版本变更说明

1.0.0:封装基础工具类(down)

1.0.1:丰富接口返回封装类的方法(down)

1.0.2:增加kv配置模型(down)

1.0.3:增加异常枚举配置体系(todo)

四、未来规划

  1. 增加异常枚举配置体系
  2. 完善三元组对象,四元组对象
上一篇:hdu1019 Least Common Multiple


下一篇:最长公共子串 二维数组 Go实现