anderx 3 gadi atpakaļ
vecāks
revīzija
14f7084dcc

+ 219 - 0
src/main/java/com/goafanti/RD/bo/InputExcelRdDetails.java

@@ -0,0 +1,219 @@
+package com.goafanti.RD.bo;
+
+import com.goafanti.common.constant.ErrorConstants;
+import com.goafanti.common.utils.Param;
+import com.goafanti.common.utils.excel.Excel;
+
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+public class InputExcelRdDetails  extends InputRdDetails{
+
+
+
+    /**
+     * 公司名称
+     */
+    @Excel(name="公司名称")
+    private String userName;
+
+    /**
+     * 研发活动编号
+     */
+    @Excel(name="研发活动编号")
+    private String rdNo;
+
+    /**
+     * 知识产权编号
+     */
+    @Excel(name="知识产权编号")
+    private String ipNo;
+
+    /**
+     * 发研活动名称
+     */
+    @Excel(name="研发活动名称")
+    private String rdName;
+
+
+    /**
+     * 开始时间
+     */
+    @Excel(name="开始时间")
+    private String rdStartStr;
+
+    /**
+     * 结束时间
+     */
+    @Excel(name="结束时间")
+    private String rdEndStr;
+
+    /**
+     * 技术领域
+     */
+    @Excel(name="技术领域")
+    private String technicalField;
+
+    /**
+     * 技术来源
+     */
+    @Excel(name="技术来源")
+    private String technologySource;
+
+    /**
+     * 研发经费总预算(万元)
+     */
+    @Excel(name="研发经费总预算(万元)")
+    private BigDecimal totalAmount;
+
+    /**
+     * 研发经费近三年总支出(万元)
+     */
+    @Excel(name="研发经费近三年总支出(万元)")
+    private BigDecimal recentThreeAmount;
+
+    /**
+     * 研发目的及组织实施方式
+     */
+    @Excel(name="研发目的及组织实施方式")
+    private String rdObjective;
+
+    /**
+     * 核心技术及创新点
+     */
+    @Excel(name="核心技术及创新点")
+    private String coreTechnology;
+
+    /**
+     * 取得的创段性成果
+     */
+    @Excel(name="取得的创段性成果")
+    private String achieveResults;
+
+
+    @Override
+    public String getTechnicalField() {
+        return technicalField;
+    }
+
+    @Override
+    public void setTechnicalField(String technicalField) {
+        this.technicalField = technicalField;
+    }
+
+    @Override
+    public String getTechnologySource() {
+        return technologySource;
+    }
+
+    @Override
+    public void setTechnologySource(String technologySource) {
+        this.technologySource = technologySource;
+    }
+
+    @Override
+    public BigDecimal getTotalAmount() {
+        return totalAmount;
+    }
+
+    @Override
+    public void setTotalAmount(BigDecimal totalAmount) {
+        this.totalAmount = totalAmount;
+    }
+
+    @Override
+    public BigDecimal getRecentThreeAmount() {
+        return recentThreeAmount;
+    }
+
+    @Override
+    public void setRecentThreeAmount(BigDecimal recentThreeAmount) {
+        this.recentThreeAmount = recentThreeAmount;
+    }
+
+    @Override
+    public String getRdObjective() {
+        return rdObjective;
+    }
+
+    @Override
+    public void setRdObjective(String rdObjective) {
+        this.rdObjective = rdObjective;
+    }
+
+    @Override
+    public String getCoreTechnology() {
+        return coreTechnology;
+    }
+
+    @Override
+    public void setCoreTechnology(String coreTechnology) {
+        this.coreTechnology = coreTechnology;
+    }
+
+    @Override
+    public String getAchieveResults() {
+        return achieveResults;
+    }
+
+    @Override
+    public void setAchieveResults(String achieveResults) {
+        this.achieveResults = achieveResults;
+    }
+
+    public String getRdStartStr() {
+        return rdStartStr;
+    }
+
+    public void setRdStartStr(String rdStartStr) {
+        this.rdStartStr = rdStartStr;
+    }
+
+    public String getRdEndStr() {
+        return rdEndStr;
+    }
+
+    public void setRdEndStr(String rdEndStr) {
+        this.rdEndStr = rdEndStr;
+    }
+
+    @Override
+    public String getUserName() {
+        return userName;
+    }
+
+    @Override
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    @Override
+    public String getRdNo() {
+        return rdNo;
+    }
+
+    @Override
+    public void setRdNo(String rdNo) {
+        this.rdNo = rdNo;
+    }
+
+    @Override
+    public String getIpNo() {
+        return ipNo;
+    }
+
+    @Override
+    public void setIpNo(String ipNo) {
+        this.ipNo = ipNo;
+    }
+
+    @Override
+    public String getRdName() {
+        return rdName;
+    }
+
+    @Override
+    public void setRdName(String rdName) {
+        this.rdName = rdName;
+    }
+}

+ 15 - 8
src/main/java/com/goafanti/RD/service/impl/RDServiceImpl.java

@@ -1,5 +1,6 @@
 package com.goafanti.RD.service.impl;
 
+import com.goafanti.RD.bo.InputExcelRdDetails;
 import com.goafanti.RD.bo.InputRdDetails;
 import com.goafanti.RD.bo.InputRdList;
 import com.goafanti.RD.bo.OutRdDetails;
@@ -67,15 +68,21 @@ public class RDServiceImpl extends BaseMybatisDao<RdDetailsMapper> implements RD
 
     @Override
     public Object batchList(MultipartFile file) {
+        NewExcelUtil<InputExcelRdDetails> newExcelUtil=new NewExcelUtil<InputExcelRdDetails>(InputExcelRdDetails.class);
+        List<InputExcelRdDetails> list = null;
+        try {
+            list = newExcelUtil.importExcel(file.getInputStream());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
 
-        List<InputRdDetails> list=  pushRdDetails(file);
-
+//        List<InputRdDetails> list=  pushRdDetails(file);
         //新增
         return insertBatch(list);
     }
 
-    private List<InputRdDetails> pushRdDetails(MultipartFile file) {
-        List<InputRdDetails> list=new ArrayList<>();
+    private List<InputExcelRdDetails> pushRdDetails(MultipartFile file) {
+        List<InputExcelRdDetails> list=new ArrayList<>();
         Workbook workbook = ExcelUtils.getWorkBook(file);
         Sheet sheet=null;
         //创建一个对象,用来存储数据
@@ -129,7 +136,7 @@ public class RDServiceImpl extends BaseMybatisDao<RdDetailsMapper> implements RD
                 int firstCellNum = row.getFirstCellNum();
                 //获得当前行的列数
                 int lastCellNum = row.getLastCellNum();
-                InputRdDetails in = new InputRdDetails();
+                InputExcelRdDetails in = new InputExcelRdDetails();
                 for (int cellNum = (firstCellNum); cellNum < lastCellNum; cellNum++) {
                     Cell cell = row.getCell(cellNum);
                     try {
@@ -197,11 +204,11 @@ public class RDServiceImpl extends BaseMybatisDao<RdDetailsMapper> implements RD
 
 
 
-    private Map<String,Object> insertBatch(List<InputRdDetails> list) {
+    private Map<String,Object> insertBatch(List<InputExcelRdDetails> list) {
         Map<String,Object> map=new HashMap<>();
-        List<InputRdDetails> relust= new ArrayList<>();
+        List<InputExcelRdDetails> relust= new ArrayList<>();
         List<String>errors=new ArrayList<>();
-        for (InputRdDetails in : list) {
+        for (InputExcelRdDetails in : list) {
             boolean falg = checkRdNo(in.getRdNo());
             if (falg){
                 errors.add(in.getRdNo());

+ 2 - 1
src/main/java/com/goafanti/common/dao/RdDetailsMapper.java

@@ -1,5 +1,6 @@
 package com.goafanti.common.dao;
 
+import com.goafanti.RD.bo.InputExcelRdDetails;
 import com.goafanti.RD.bo.InputRdDetails;
 import com.goafanti.RD.bo.OutRdDetails;
 import com.goafanti.common.model.RdDetails;
@@ -23,5 +24,5 @@ public interface RdDetailsMapper {
 
     int checkRdNo(String rdNo);
 
-    void insertBatch(List<InputRdDetails> list);
+    void insertBatch(List<InputExcelRdDetails> list);
 }

+ 34 - 0
src/main/java/com/goafanti/common/utils/DateUtils.java

@@ -8,6 +8,7 @@ import java.util.Date;
 
 
 import com.goafanti.common.error.BusinessException;
+import org.apache.commons.lang3.time.DateFormatUtils;
 
 public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
 
@@ -21,6 +22,11 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
 
 	public static final String	DAY_SPAN		= "daySpan";
 
+	private static String[] parsePatterns = {
+			"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
+			"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
+			"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
+
 	/**
 	 * Determines how two dates compare up to no more than the specified most
 	 * significant field.
@@ -477,4 +483,32 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
 		ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
 		return Date.from(zdt.toInstant());
 	}
+
+	/**
+	 * 日期路径 即年/月/日 如2018/08/08
+	 */
+	public static final String datePath()
+	{
+		Date now = new Date();
+		return DateFormatUtils.format(now, "yyyy/MM/dd");
+	}
+
+	/**
+	 * 日期型字符串转化为日期 格式
+	 */
+	public static Date parseDate(Object str)
+	{
+		if (str == null)
+		{
+			return null;
+		}
+		try
+		{
+			return parseDate(str.toString(), parsePatterns);
+		}
+		catch (ParseException e)
+		{
+			return null;
+		}
+	}
 }

+ 21 - 0
src/main/java/com/goafanti/common/utils/StringUtils.java

@@ -1,5 +1,6 @@
 package com.goafanti.common.utils;
 
+import java.util.Map;
 import java.util.regex.Pattern;
 
 public class StringUtils extends org.apache.commons.lang3.StringUtils {
@@ -25,6 +26,26 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
 	}
 
 
+	/**
+	 * * 判断一个Map是否为空
+	 *
+	 * @param map 要判断的Map
+	 * @return true:非空 false:空
+	 */
+	public static boolean isNotEmpty(Map<?, ?> map)
+	{
+		return !isEmpty(map);
+	}
+	/**
+	 * * 判断一个Map是否为空
+	 *
+	 * @param map 要判断的Map
+	 * @return true:为空 false:非空
+	 */
+	public static boolean isEmpty(Map<?, ?> map)
+	{
+		return isNull(map) || map.isEmpty();
+	}
 
 	/**
 	 * * 判断一个对象数组是否为空

+ 11 - 0
src/main/java/com/goafanti/common/utils/excel/Excel.java

@@ -121,11 +121,22 @@ public @interface Excel
      */
     public boolean isStatistics() default false;
 
+
     /**
      * 导出字段对齐方式(0:默认;1:靠左;2:居中;3:靠右)
      */
     Align align() default Align.AUTO;
 
+    /**
+     * 自定义数据处理器
+     */
+    public Class<?> handler() default ExcelHandlerAdapter.class;
+
+    /**
+     * 自定义数据处理器参数
+     */
+    public String[] args() default {};
+
     public enum Align
     {
         AUTO(0), LEFT(1), CENTER(2), RIGHT(3);

+ 19 - 0
src/main/java/com/goafanti/common/utils/excel/ExcelHandlerAdapter.java

@@ -0,0 +1,19 @@
+package com.goafanti.common.utils.excel;
+
+/**
+ * Excel数据格式处理适配器
+ *
+ * @author ruoyi
+ */
+public interface ExcelHandlerAdapter
+{
+    /**
+     * 格式化
+     *
+     * @param value 单元格数据值
+     * @param args excel注解args参数组
+     *
+     * @return 处理后的值
+     */
+    Object format(Object value, String[] args);
+}

+ 93 - 0
src/main/java/com/goafanti/common/utils/excel/FileUtils.java

@@ -3,8 +3,12 @@ package com.goafanti.common.utils.excel;
 import java.io.*;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
+import java.util.UUID;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+
+import com.goafanti.common.utils.DateUtils;
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.ArrayUtils;
 
 import com.goafanti.common.utils.StringUtils;
@@ -254,4 +258,93 @@ public class FileUtils extends org.apache.commons.io.FileUtils
         return fileName.substring(separatorIndex + 1).toLowerCase();
     }
 
+
+    /**
+     * 写数据到文件中
+     *
+     * @param data 数据
+     * @return 目标文件
+     * @throws IOException IO异常
+     */
+    public static String writeImportBytes(byte[] data) throws IOException
+    {
+        //文件图片存放地址
+        String importPath="F:/data/public/upload";
+        return writeBytes(data, importPath);
+    }
+
+    /**
+     * 写数据到文件中
+     *
+     * @param data 数据
+     * @param uploadDir 目标文件
+     * @return 目标文件
+     * @throws IOException IO异常
+     */
+    public static String writeBytes(byte[] data, String uploadDir) throws IOException
+    {
+        FileOutputStream fos = null;
+        String pathName = "";
+        try
+        {
+            String extension = getFileExtendName(data);
+            pathName = DateUtils.datePath() + "/" + UUID.randomUUID() + "." + extension;
+            File file = getAbsoluteFile(uploadDir, pathName);
+            fos = new FileOutputStream(file);
+            fos.write(data);
+        }
+        finally
+        {
+            fos.close();
+        }
+        return getPathFileName(uploadDir, pathName);
+    }
+
+    private static String getPathFileName(String uploadDir, String pathName) {
+        return uploadDir+"/ExcelFile/"+pathName;
+    }
+
+    public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
+    {
+        File desc = new File(uploadDir + File.separator + fileName);
+
+        if (!desc.exists())
+        {
+            if (!desc.getParentFile().exists())
+            {
+                desc.getParentFile().mkdirs();
+            }
+        }
+        return desc;
+    }
+
+
+    /**
+     * 获取图像后缀
+     *
+     * @param photoByte 图像数据
+     * @return 后缀名
+     */
+    public static String getFileExtendName(byte[] photoByte)
+    {
+        String strFileExtendName = "jpg";
+        if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
+                && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))
+        {
+            strFileExtendName = "gif";
+        }
+        else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))
+        {
+            strFileExtendName = "jpg";
+        }
+        else if ((photoByte[0] == 66) && (photoByte[1] == 77))
+        {
+            strFileExtendName = "bmp";
+        }
+        else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))
+        {
+            strFileExtendName = "png";
+        }
+        return strFileExtendName;
+    }
 }

+ 28 - 20
src/main/java/com/goafanti/common/utils/excel/NewExcelUtil.java

@@ -8,7 +8,6 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.lang.reflect.Array;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.math.BigDecimal;
@@ -28,7 +27,6 @@ import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.ss.util.CellRangeAddressList;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.xssf.streaming.SXSSFWorkbook;
 import org.apache.poi.xssf.usermodel.*;
 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
 import org.slf4j.Logger;
@@ -40,6 +38,7 @@ import com.goafanti.common.error.BusinessException;
 import com.goafanti.common.utils.DateUtils;
 import com.goafanti.common.utils.StringUtils;
 import com.goafanti.common.utils.excel.Excel.ColumnType;
+import com.goafanti.common.utils.excel.Excel.Type;
 
 /**
  * 	Excel相关处理
@@ -133,7 +132,7 @@ public class NewExcelUtil<T> {
 		createExcelField();
 		createWorkbook();
 	}
-	public void init(List<T> list, String sheetName, String title, Type type)
+	public void init(List<T> list, String sheetName, String title, Excel.Type type)
 	{
 		if (list == null)
 		{
@@ -1142,7 +1141,7 @@ public class NewExcelUtil<T> {
 	 */
 	public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception
 	{
-		this.type = Type.IMPORT;
+		this.type = Excel.Type.IMPORT;
 		this.wb = WorkbookFactory.create(is);
 		List<T> list = new ArrayList<T>();
 		// 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet
@@ -1260,7 +1259,7 @@ public class NewExcelUtil<T> {
 					{
 						if (val instanceof String)
 						{
-							val = DateUtils.parseDate(val);
+							val = DateUtils.parseDate((String) val);
 						}
 						else if (val instanceof Double)
 						{
@@ -1287,7 +1286,7 @@ public class NewExcelUtil<T> {
 						{
 							val = dataFormatHandlerAdapter(val, attr);
 						}
-						else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures))
+						else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty((CharSequence) pictures))
 						{
 							PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey());
 							if (image == null)
@@ -1367,21 +1366,7 @@ public class NewExcelUtil<T> {
 
 
 
-	public enum Type
-	{
-		ALL(0), EXPORT(1), IMPORT(2);
-		private final int value;
 
-		Type(int value)
-		{
-			this.value = value;
-		}
-
-		public int value()
-		{
-			return this.value;
-		}
-	}
 
 	/**
 	 * 获取Excel2003图片
@@ -1489,5 +1474,28 @@ public class NewExcelUtil<T> {
 	}
 
 
+	/**
+	 * 数据处理器
+	 *
+	 * @param value 数据值
+	 * @param excel 数据注解
+	 * @return
+	 */
+	public String dataFormatHandlerAdapter(Object value, Excel excel)
+	{
+		try
+		{
+			Object instance = excel.handler().newInstance();
+			Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class });
+			value = formatMethod.invoke(instance, value, excel.args());
+		}
+		catch (Exception e)
+		{
+			log.error("不能格式化数据 " + excel.handler(), e.getMessage());
+		}
+		return Convert.toStr(value);
+	}
+
+
 
 }

+ 405 - 0
src/main/java/com/goafanti/common/utils/excel/ReflectUtils.java

@@ -0,0 +1,405 @@
+package com.goafanti.common.utils.excel;
+
+import com.goafanti.common.utils.DateUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.*;
+import java.util.Date;
+
+/**
+ * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
+ *
+ * @author ruoyi
+ */
+@SuppressWarnings("rawtypes")
+public class ReflectUtils
+{
+    private static final String SETTER_PREFIX = "set";
+
+    private static final String GETTER_PREFIX = "get";
+
+    private static final String CGLIB_CLASS_SEPARATOR = "$$";
+
+    private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
+
+    /**
+     * 调用Getter方法.
+     * 支持多级,如:对象名.对象名.方法
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> E invokeGetter(Object obj, String propertyName)
+    {
+        Object object = obj;
+        for (String name : StringUtils.split(propertyName, "."))
+        {
+            String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
+            object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
+        }
+        return (E) object;
+    }
+
+    /**
+     * 调用Setter方法, 仅匹配方法名。
+     * 支持多级,如:对象名.对象名.方法
+     */
+    public static <E> void invokeSetter(Object obj, String propertyName, E value)
+    {
+        Object object = obj;
+        String[] names = StringUtils.split(propertyName, ".");
+        for (int i = 0; i < names.length; i++)
+        {
+            if (i < names.length - 1)
+            {
+                String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
+                object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
+            }
+            else
+            {
+                String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
+                invokeMethodByName(object, setterMethodName, new Object[] { value });
+            }
+        }
+    }
+
+    /**
+     * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> E getFieldValue(final Object obj, final String fieldName)
+    {
+        Field field = getAccessibleField(obj, fieldName);
+        if (field == null)
+        {
+            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
+            return null;
+        }
+        E result = null;
+        try
+        {
+            result = (E) field.get(obj);
+        }
+        catch (IllegalAccessException e)
+        {
+            logger.error("不可能抛出的异常{}", e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
+     */
+    public static <E> void setFieldValue(final Object obj, final String fieldName, final E value)
+    {
+        Field field = getAccessibleField(obj, fieldName);
+        if (field == null)
+        {
+            // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
+            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
+            return;
+        }
+        try
+        {
+            field.set(obj, value);
+        }
+        catch (IllegalAccessException e)
+        {
+            logger.error("不可能抛出的异常: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 直接调用对象方法, 无视private/protected修饰符.
+     * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
+     * 同时匹配方法名+参数类型,
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
+            final Object[] args)
+    {
+        if (obj == null || methodName == null)
+        {
+            return null;
+        }
+        Method method = getAccessibleMethod(obj, methodName, parameterTypes);
+        if (method == null)
+        {
+            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
+            return null;
+        }
+        try
+        {
+            return (E) method.invoke(obj, args);
+        }
+        catch (Exception e)
+        {
+            String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
+            throw convertReflectionExceptionToUnchecked(msg, e);
+        }
+    }
+
+    /**
+     * 直接调用对象方法, 无视private/protected修饰符,
+     * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
+     * 只匹配函数名,如果有多个同名函数调用第一个。
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args)
+    {
+        Method method = getAccessibleMethodByName(obj, methodName, args.length);
+        if (method == null)
+        {
+            // 如果为空不报错,直接返回空。
+            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
+            return null;
+        }
+        try
+        {
+            // 类型转换(将参数数据类型转换为目标方法参数类型)
+            Class<?>[] cs = method.getParameterTypes();
+            for (int i = 0; i < cs.length; i++)
+            {
+                if (args[i] != null && !args[i].getClass().equals(cs[i]))
+                {
+                    if (cs[i] == String.class)
+                    {
+                        args[i] = Convert.toStr(args[i]);
+                        if (StringUtils.endsWith((String) args[i], ".0"))
+                        {
+                            args[i] = StringUtils.substringBefore((String) args[i], ".0");
+                        }
+                    }
+                    else if (cs[i] == Integer.class)
+                    {
+                        args[i] = Convert.toInt(args[i]);
+                    }
+                    else if (cs[i] == Long.class)
+                    {
+                        args[i] = Convert.toLong(args[i]);
+                    }
+                    else if (cs[i] == Double.class)
+                    {
+                        args[i] = Convert.toDouble(args[i]);
+                    }
+                    else if (cs[i] == Float.class)
+                    {
+                        args[i] = Convert.toFloat(args[i]);
+                    }
+                    else if (cs[i] == Date.class)
+                    {
+                        if (args[i] instanceof String)
+                        {
+                            args[i] = DateUtils.parseDate(args[i]);
+                        }
+                        else
+                        {
+                            args[i] = DateUtil.getJavaDate((Double) args[i]);
+                        }
+                    }
+                    else if (cs[i] == boolean.class || cs[i] == Boolean.class)
+                    {
+                        args[i] = Convert.toBool(args[i]);
+                    }
+                }
+            }
+            return (E) method.invoke(obj, args);
+        }
+        catch (Exception e)
+        {
+            String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
+            throw convertReflectionExceptionToUnchecked(msg, e);
+        }
+    }
+
+    /**
+     * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
+     * 如向上转型到Object仍无法找到, 返回null.
+     */
+    public static Field getAccessibleField(final Object obj, final String fieldName)
+    {
+        // 为空不报错。直接返回 null
+        if (obj == null)
+        {
+            return null;
+        }
+        Validate.notBlank(fieldName, "fieldName can't be blank");
+        for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
+        {
+            try
+            {
+                Field field = superClass.getDeclaredField(fieldName);
+                makeAccessible(field);
+                return field;
+            }
+            catch (NoSuchFieldException e)
+            {
+                continue;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
+     * 如向上转型到Object仍无法找到, 返回null.
+     * 匹配函数名+参数类型。
+     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
+     */
+    public static Method getAccessibleMethod(final Object obj, final String methodName,
+            final Class<?>... parameterTypes)
+    {
+        // 为空不报错。直接返回 null
+        if (obj == null)
+        {
+            return null;
+        }
+        Validate.notBlank(methodName, "methodName can't be blank");
+        for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
+        {
+            try
+            {
+                Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
+                makeAccessible(method);
+                return method;
+            }
+            catch (NoSuchMethodException e)
+            {
+                continue;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
+     * 如向上转型到Object仍无法找到, 返回null.
+     * 只匹配函数名。
+     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
+     */
+    public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum)
+    {
+        // 为空不报错。直接返回 null
+        if (obj == null)
+        {
+            return null;
+        }
+        Validate.notBlank(methodName, "methodName can't be blank");
+        for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
+        {
+            Method[] methods = searchType.getDeclaredMethods();
+            for (Method method : methods)
+            {
+                if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum)
+                {
+                    makeAccessible(method);
+                    return method;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
+     */
+    public static void makeAccessible(Method method)
+    {
+        if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
+                && !method.isAccessible())
+        {
+            method.setAccessible(true);
+        }
+    }
+
+    /**
+     * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
+     */
+    public static void makeAccessible(Field field)
+    {
+        if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
+                || Modifier.isFinal(field.getModifiers())) && !field.isAccessible())
+        {
+            field.setAccessible(true);
+        }
+    }
+
+    /**
+     * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
+     * 如无法找到, 返回Object.class.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Class<T> getClassGenricType(final Class clazz)
+    {
+        return getClassGenricType(clazz, 0);
+    }
+
+    /**
+     * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
+     * 如无法找到, 返回Object.class.
+     */
+    public static Class getClassGenricType(final Class clazz, final int index)
+    {
+        Type genType = clazz.getGenericSuperclass();
+
+        if (!(genType instanceof ParameterizedType))
+        {
+            logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
+            return Object.class;
+        }
+
+        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
+
+        if (index >= params.length || index < 0)
+        {
+            logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+                    + params.length);
+            return Object.class;
+        }
+        if (!(params[index] instanceof Class))
+        {
+            logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
+            return Object.class;
+        }
+
+        return (Class) params[index];
+    }
+
+    public static Class<?> getUserClass(Object instance)
+    {
+        if (instance == null)
+        {
+            throw new RuntimeException("Instance must not be null");
+        }
+        Class clazz = instance.getClass();
+        if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR))
+        {
+            Class<?> superClass = clazz.getSuperclass();
+            if (superClass != null && !Object.class.equals(superClass))
+            {
+                return superClass;
+            }
+        }
+        return clazz;
+
+    }
+
+    /**
+     * 将反射时的checked exception转换为unchecked exception.
+     */
+    public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e)
+    {
+        if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
+                || e instanceof NoSuchMethodException)
+        {
+            return new IllegalArgumentException(msg, e);
+        }
+        else if (e instanceof InvocationTargetException)
+        {
+            return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
+        }
+        return new RuntimeException(msg, e);
+    }
+}