目录
介绍
代码
jar pom
注解
工具类
Sheet页设置
BaseBean/ResultForm说明
使用流程示例
Excel模板导出及导入解析
Excel导入工具类
使用流程示例
Excel导出是我们在项目中经常使用到的功能,市面上成熟的导出工具包用起来比较的繁琐,而且定制化不高,在我们想自己编写一些特殊功能时不太好用,因此决定自己写一个简单的基于注解的Excel多Sheet导出。
在设计Excel导出@ExcelField注解之前,我们项目中也是用到了Swagger工具注解,上面包含了字段的说明标题,因此在编写自定义注解时省略了标题属性,通过直接获取swagger的@ApiModelProperty的字段说明来获取字段的标题,小伙伴们可以通过自己添加@ExcelField注解的自定义属性来替代。
本导出工具类是基于阿帕奇的POI5.1.1版本,pom jar描述如下:
org.apache.poi poi 5.1.0
使用流程为在导出实体类上添加导出注解@ExcelField,设置是否导出数据,或是否是模板导出属性,之后调用下载发放即可,上代码
package com.pride.sun.common;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Excel自定义注解
*
* @author lpw
* @date 2020-04-19
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelFiled {
/**
* 是否是导出属性
*
* @return
*/
boolean isExport() default true;
/**
* 是否是导入属性
*
* @return
*/
boolean isImport() default true;
/**
* 是否是父ID属性
*
* @return
*/
boolean isPId() default false;
}
package com.pride.sun.common;
import com.pride.sun.base.BaseBean;
import com.pride.sun.result.ResultForm;
import io.swagger.annotations.ApiModel;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.minbox.framework.web.response.ResponseWrapper;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* Excel工具类
*
* @param
* @author lpw
*/
public class ExcelUtils {
/**
* 行高
*/
private int rowHeight = 400;
/**
* 列宽
*/
private int colWidth = 3000;
/**
* 工作页
*/
private Workbook workbook = new HSSFWorkbook();
/**
* 默认标题
*/
private String defaultTitle;
/**
* sheet页集合
*/
private List sheetList = new ArrayList<>();
/**
* Class类工具
*/
private ClassUtils util = new ClassUtils();
public ExcelUtils() {
}
public ExcelUtils(String title) {
defaultTitle = title;
}
public ExcelUtils(int rowHeight, int colWidth, String title) {
this.rowHeight = rowHeight;
this.colWidth = colWidth;
this.defaultTitle = title;
}
/**
* 默认文档设置文档
*/
private void initWorkbook() {
if (CollectionUtils.isNotEmpty(sheetList)) {
if (StringUtils.isEmpty(defaultTitle)) {
defaultTitle = getDefaultTitle(sheetList.get(0));
}
sheetList.forEach(v -> {
//设置默认标题行
if (StringUtils.isEmpty(v.getSheetTitle())) {
v.setSheetTitle(getDefaultTitle(v));
}
v.parseFieldAnnotation();
// 创建工作页
v.setSheet(workbook.createSheet(v.getSheetTitle()));
// 设置默认列宽
v.getSheet().setDefaultColumnWidth(colWidth);
//设置冻结行
v.getSheet().createFreezePane(0, 2);
//标题样式
titleStyleSetting(v);
});
}
}
/**
* 加载生成Excel
*
* @throws Exception
*/
public ResultForm initAndDownload() throws Exception {
initWorkbook();
createExcel();
downloadExcel();
return new ResultForm(ResultForm.SUCCESS, "导出成功");
}
/**
* 导出Excel
*
* @param dataList
* @param
*/
public static ResultForm exportExcel(List dataList, Class eClass) {
return exportExcel(dataList, eClass, null);
}
/**
* 导出Excel
*
* @param dataList
* @param
*/
public static ResultForm exportExcel(List dataList, Class eClass, String title) {
try {
if (eClass == null) {
return new ResultForm("未指定类对象");
}
if (CollectionUtils.isNotEmpty(dataList)) {
ExcelUtils excel = new ExcelUtils<>();
excel.defaultTitle = title;
excel.addSheet(eClass, title, dataList, false);
return excel.initAndDownload();
}
return new ResultForm(ResultForm.TIP, "未查到需要导出的数据");
} catch (Exception e) {
return new ResultForm(e);
}
}
/**
* 下载模板
*
* @param eClass
* @param
*/
public static ResultForm downLoadModel(Class eClass) {
return downLoadModel(eClass, null);
}
/**
* 下载模板
*
* @param eClass
* @param
*/
public static ResultForm downLoadModel(Class eClass, String title) {
try {
if (eClass != null) {
ExcelUtils excel = new ExcelUtils<>();
excel.defaultTitle = title;
excel.addSheet(eClass, title, null, true);
return excel.initAndDownload();
}
return new ResultForm(ResultForm.ERROR, "类对象不能为空");
} catch (Exception e) {
return new ResultForm(e);
}
}
/**
* 添加sheet页
*
* @param eClass
* @param sheetTitle
* @param dataList
* @param
*/
public MySheet addSheet(Class eClass, String sheetTitle, List dataList, Boolean isDownLoad) {
MySheet mySheet = new MySheet<>();
mySheet.setSheetTitle(sheetTitle);
mySheet.setSheetClass(eClass);
mySheet.setDataList(dataList);
mySheet.setDownloadMode(isDownLoad);
sheetList.add(mySheet);
return mySheet;
}
/**
* 获取类标题
*
* @param mySheet
* @return
*/
private String getDefaultTitle(MySheet mySheet) {
Annotation[] ans = mySheet.getSheetClass().getAnnotations();
for (Annotation temp : ans) {
if (temp instanceof ApiModel) {
return ((ApiModel) temp).description();
}
}
return null;
}
/**
* 标题、列名相关设置
*/
private void titleStyleSetting(MySheet mySheet) {
List
package com.pride.sun.common;
import com.alibaba.fastjson.annotation.JSONField;
import com.pride.sun.base.BaseBean;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Sheet;
import java.lang.reflect.Field;
import java.util.*;
/**
* 自定义Sheet封装类
*
* @author lpw
* @date 2021-07-19
*/
@Data
public class MySheet {
/**
* sheet页
*/
private Sheet sheet;
/**
* sheet页映射类
*/
private Class sheetClass;
/**
* sheet标题
*/
private String sheetTitle;
/**
* Sheet样式
*/
private CellStyle cellStyle;
/**
* 起始位置
*/
private int rowIndex = 0;
/**
* 列属性集合
*/
private List> colList = new ArrayList<>();
/**
* 列样式集合
*/
private List styleList = new ArrayList<>();
/**
* 是否是 下载导出模板
*/
private boolean isDownloadMode = false;
/**
* sheet页数据
*/
private List dataList;
/**
* 通过注解获取列相关注解属性
*/
void parseFieldAnnotation() {
Field[] fields = sheetClass.getDeclaredFields();
for (Field temp : fields) {
if (temp.isAnnotationPresent(ExcelFiled.class) && temp.isAnnotationPresent(ApiModelProperty.class)) {
ExcelFiled excelFiled = temp.getAnnotation(ExcelFiled.class);
//swagger注解用于获取字段标题,可替换
ApiModelProperty api = temp.getAnnotation(ApiModelProperty.class);
Map fieldMap = new HashMap<>();
fieldMap.put("width", 6000);
fieldMap.put("color", 0x08);
fieldMap.put("text", api.value());
fieldMap.put("methodName", "get" + convertMethodName(temp.getName()));
//日期格式设置,这里采用了fastJson的日期注解判断,获取日期格式,可根据需要替换
//到自定义注解ExcelField属性中
if (temp.getType() == Date.class && temp.isAnnotationPresent(JSONField.class)) {
JSONField dateJsonField = temp.getAnnotation(JSONField.class);
if (StringUtils.isNotEmpty(dateJsonField.format())) {
fieldMap.put("dateFormat", dateJsonField.format());
}
}
//判断是否是下载Excel模板
if (isDownloadMode && excelFiled.isImport()) {
colList.add(fieldMap);
} else if (!isDownloadMode && excelFiled.isExport()) {
colList.add(fieldMap);
}
}
}
}
/**
* 首字母大写
*
* @param fieldName
* @return
*/
public String convertMethodName(String fieldName) {
String newField = fieldName.substring(1);
return fieldName.substring(0, 1).toUpperCase() + newField;
}
}
其中BaseBean为项目中导出实体的公共父类,及通用属性都放置其中,可根据实际需要修改获去除。
ResultForm为项目中公共返回封装实体,也可根据实际需要去除。
单Sheet页使用流程示例:(sheet页标题默认为实体swagger实体注解,可根据需要修改)
1,在实体上添加导出注解
2.获取实体集合数据,调用工具导出方法,传入集合,导出实体类.class,Excel标题(可选)默认是swagger的实体注解说明。
public ResultForm exportAuditedPlanExcel(T t) {
List dataList= dao.selectList(t);
return ExcelUtils.exportExcel(dataList, T.class);
}
public ResultForm exportDicCommonValue(E e) {
List beans = dao.selectList(e);
return ExcelUtils.exportExcel(beans, E.class, “Excel文件名称”);
}
多sheet导出示例,与单Sheet页导出不冲突,也可使用此方式导出单sheet页。
1.添加实体注解,同上
2.初始化工具类实例
ExcelUtils excel = new ExcelUtils<>("导出文件名称");
3.获取数据集合,添加Sheet页数据。
ExcelUtils excel = new ExcelUtils<>("导出文件名称");
//获取数据集合
List dataList = dao.selectList();
//第一Sheet页
excel.addSheet(T.class, "sheet标题", dataList,false);
List dataList2 = dao.selectList();
//第二Sheet页
excel.addSheet(E.class, "sheet2标题", dataList2,false);
4.调用导出
ExcelUtils excel = new ExcelUtils<>("导出文件名称");
//获取数据集合
List dataList = dao.selectList();
//第一Sheet页
excel.addSheet(T.class, "sheet标题", dataList,false);
List dataList2 = dao.selectList();
//第二Sheet页
excel.addSheet(E.class, "sheet2标题", dataList2,false);
//导出
excel.initAndDownload();
上面的最后一个布尔参数为设置是否是下载模板属性,此属性控制sheet页是否按照实体注解顺序只导出标题列,不导出数据,方便后面导入解析。当我们遇到需要下载Excel导入模板,并且需要有其他sheet页的数据作参考时,可通过这个属性来控制,如第一sheet是导入模板(数据集合可传null),第二sheet页为字典值。则可根据此属性控制。
以上为导出的完整示例及代码。
上面我们介绍了导出工具代码及流程,并在最后说明了一个布尔参数isDownLoadModel
在自定义注解@ExcelField中我们也看到了有个属性值isImport.这个属性是用来标记是否为导出模板列,可以控制这个属性的值在实体中标识是否是导出模板属性,并且后续我们会根据这个属性来判断并解析导入Excel的数据。
注:导入为单sheet页导入,默认为第一个sheet页的数据,可根据自己需要扩展
package com.pride.sun.common;
import com.pride.sun.base.BaseBean;
import com.pride.sun.exception.TipException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.multipart.MultipartFile;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static org.apache.poi.ss.usermodel.CellType.BLANK;
/**
* @author lpw.
* @des Excel 导入 工具类
*/
public class ExcelReadUtil {
private Class claze;
private final String format = "yyyy-MM-dd HH:mm:ss";
public ExcelReadUtil(Class claze) {
this.claze = claze;
}
/**
* 基于注解读取excel
*
* @param file 文件
* @return List List 集合
*/
public List readExcel(MultipartFile file) throws Exception {
verifyExcelFile(file);
POIFSFileSystem fs = null;
Field field;
List list = new ArrayList<>();
T entity = null;
// 带注解并排序好的字段
List fieldList = getFieldList();
int size = fieldList.size();
fs = new POIFSFileSystem(file.getInputStream());
HSSFWorkbook workbook = new HSSFWorkbook(fs);
HSSFSheet sheet = workbook.getSheetAt(0);
// 不准确
int rowLength = sheet.getLastRowNum();
//第三行开始遍历
for (int i = 2; i <= rowLength; i++) {
HSSFRow row = sheet.getRow(i);
entity = (T) claze.newInstance();
for (int j = 0; j < size; j++) {
try {
HSSFCell cell = row.getCell(j);
field = fieldList.get(j);
field.setAccessible(true);
field.set(entity, covertAttrType(field, cell));
} catch (Exception e) {
String eMsg = "第" + (i + 1) + "行 第" + (j + 1) + "列;";
throw new TipException(eMsg + e.getMessage());
}
}
list.add(entity);
}
return list;
}
/**
* 导入文件校验
*
* @param file
*/
private void verifyExcelFile(MultipartFile file) {
if (file == null || file.isEmpty()) {
throw new TipException("文件大小不能为空");
}
String fileName = file.getOriginalFilename();
if (StringUtils.isEmpty(fileName)) {
throw new TipException("文件名称不能为空");
}
String lastName = fileName.substring(fileName.indexOf("."));
if (!".xls".equals(lastName) && !".xlsx".equals(lastName)) {
throw new TipException("无法解析的Excel文件格式");
}
}
/**
* 获取带注解的字段
*
* @return
*/
private List getFieldList() {
Field[] fields = claze.getDeclaredFields();
// 无序
List fieldList = new ArrayList();
int length = fields.length;
Field field = null;
// 获取带注解的字段
for (int i = 0; i < length; i++) {
field = fields[i];
if (field.isAnnotationPresent(ExcelFiled.class)) {
ExcelFiled excelFiled = field.getAnnotation(ExcelFiled.class);
if (excelFiled.isImport()) {
fieldList.add(field);
}
}
}
return fieldList;
}
/**
* 类型转换 将cell 单元格格式转为 字段类型
*/
private Object covertAttrType(Field field, HSSFCell cell) {
if (null == cell || cell.getCellType() == BLANK) {
return null;
}
// 字段类型
String fieldType = field.getType().getSimpleName();
try {
String cellValue = getValue(cell);
if (StringUtils.isNotEmpty(cellValue)) {
if ("String".equals(fieldType)) {
return cellValue;
} else if ("Date".equals(fieldType)) {
//首先根据日期注解进行解析日期
if (field.isAnnotationPresent(DateTimeFormat.class)) {
DateTimeFormat timeFormat = field.getAnnotation(DateTimeFormat.class);
if (StringUtils.isNotEmpty(timeFormat.pattern())) {
return DateUtil2.parseToDate(cellValue, timeFormat.pattern());
}
}
return DateUtils.parseDate(cellValue, new String[]{format});
} else if ("int".equals(fieldType) || "Integer".equals(fieldType)) {
return Integer.parseInt(cellValue);
} else if ("double".equals(fieldType) || "Double".equals(fieldType)) {
return Double.parseDouble(cellValue);
} else if ("BigDecimal".equals(fieldType)) {
return new BigDecimal(cellValue);
} else if ("long".equals(fieldType) || "Long".equals(fieldType)) {
return new Long(cellValue);
} else {
throw new TipException("excel 单元格 格式暂不支持");
}
} else {
return null;
}
} catch (Exception e) {
if (e instanceof ParseException) {
throw new TipException("时间格式转换失败", e);
} else {
e.printStackTrace();
throw new TipException("格式转换失败");
}
}
}
/**
* 格式转为String
*
* @param cell
* @return
*/
public String getValue(Cell cell) {
if (cell == null) {
return "";
}
switch (cell.getCellType()) {
case STRING:
return cell.getRichStringCellValue().getString().trim();
case NUMERIC:
if (HSSFDateUtil.isCellDateFormatted(cell)) {
Date dt = HSSFDateUtil.getJavaDate(cell.getNumericCellValue());
return DateFormatUtils.format(dt, format);
} else {
// 防止数值变成科学计数法
String strCell = "";
Double num = cell.getNumericCellValue();
BigDecimal bd = new BigDecimal(num.toString());
if (bd != null) {
strCell = bd.toPlainString();
}
// 去除 浮点型 自动加的 .0
if (strCell.endsWith(".0")) {
strCell = strCell.substring(0, strCell.indexOf("."));
}
return strCell;
}
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case FORMULA:
return cell.getCellFormula();
case BLANK:
return "";
default:
return "";
}
}
}
1.先在实体上设置导入属性,同导入,关键属性为isImport
2.下载模板,同导出示例
3.用户填充数据后,导入excel
ResultForm importExcelData(MultipartFile excelFile)
4.创建导入工具实例,解析
ExcelReadUtil excelReadUtil = new ExcelReadUtil(T.class);
List beanList = excelReadUtil.readExcel(excelFile);
2022-07-14更新:附日期工具类DateUtil2.java,其中SystemException可替换成别的异常类,如RuntimeException。
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class DateUtil2 {
public final static Logger logger = LogManager.getLogger(DateUtil2.class);
public static final String DATE_PATTERN = "yyyy-MM-dd";
public static final String TIME_PATTERN = "HH:mm:ss";
public static final String DATE_TIME_PATTERN = DATE_PATTERN + " " + TIME_PATTERN;
public final static String FORMAT_DATE_DEFAULT = "yyyy-MM-dd";
public final static String FORMAT_DATE_YYYYMMDD = "yyyyMMdd";
public final static String FORMAT_DATE_YYYY_MM_DD = "yyyy-MM-dd";
public final static String FORMAT_DATE_PATTERN_1 = "yyyy/MM/dd";
public final static String FORMAT_DATE_PATTERN_2 = "yyyy/M/dd";
public final static String FORMAT_DATE_PATTERN_3 = "yyyy/MM/d";
public final static String FORMAT_DATE_PATTERN_4 = "yyyy/M/d";
public final static String FORMAT_DATE_YYYY_MM_DD_HHMMSS = "yyyyMMddHHmmss";
public final static String FORMAT_DATE_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
public final static String FORMAT_DATE_YYYY_MM_DD_HHMM = "yyyy-MM-dd HHmm";
public final static String FORMAT_DATE_YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
public final static String FORMAT_DATE_HH_MM = "HH:mm";
public final static String FORMAT_DATE_HH_MM_SS = "HH:mm:ss";
public final static String FORMAT_DATE_HHMM = "HHmm";
public final static String FORMAT_DATE_HHMMSS = "HHmmss";
public static final String FORMAT_DATE_YYMMDD = "yyMMdd";
public static final String FORMAT_WORK_TIME = "yyyy-MM-dd HHmmss";
public static final String FORMAT_DATE_YYYY_MM_DDHHMMSS = "yyyy-MM-ddHHmmss";
/**
* 锁对象
*/
private static final Object LOCK_OBJ = new Object();
private static Map> sdfMap = new HashMap<>();
/**
* 返回一个ThreadLocal的sdf,每个线程只会new一次sdf
*
* @param pattern
*/
private static SimpleDateFormat getSdf(final String pattern) {
ThreadLocal tl = sdfMap.get(pattern);
// 此处的双重判断和同步是为了防止sdfMap这个单例被多次put重复的sdf
if (tl == null) {
synchronized (LOCK_OBJ) {
tl = sdfMap.get(pattern);
if (tl == null) {
// 只有Map中还没有这个pattern的sdf才会生成新的sdf并放入map
// 这里是关键,使用ThreadLocal替代原来直接new SimpleDateFormat
tl = ThreadLocal.withInitial(() -> new SimpleDateFormat(pattern));
sdfMap.put(pattern, tl);
}
}
}
return tl.get();
}
/**
* 是用ThreadLocal来获取SimpleDateFormat,这样每个线程只会有一个SimpleDateFormat
*
* @param date
* @param pattern
* @return
*/
public static String formatDate(Date date, String pattern) {
return getSdf(pattern).format(date);
}
public static Date parseToDate(String dateStr, String pattern) throws ParseException {
return getSdf(pattern).parse(dateStr);
}
/**
* 把int的20170812的日期,转换成toPattern的字符串格式
*
* @param dateInt
* @param pattern
* @param toPattern
* @return
* @throws ParseException
*/
public static String parseIntToString(String dateInt, String pattern, String toPattern) {
Date date = null;
try {
date = getSdf(pattern).parse(dateInt);
} catch (ParseException e) {
e.printStackTrace();
}
return formatDate(date, toPattern);
}
public static String parseInt8ToString(Integer dateInt, String toPattern) {
if (dateInt == null) {
return "";
}
String dateString = dateInt.toString();
return parseIntToString(dateString, "yyyyMMdd", toPattern);
}
/**
* 把int的20170812的日期,转换成toPattern的字符串格式
*
* @param dateInt
* @param pattern
* @param toPattern
* @return
* @throws ParseException
*/
public static Date parseIntToDate(String dateInt, String pattern, String toPattern) throws ParseException {
return getSdf(pattern).parse(dateInt);
}
/**
* 比较两个时间是否相等。
*
* @param d1 时间1
* @param d2 时间2
* @return 相等则true。因为数据库中读出的数据为Timestamp类型(Date的子类),
* 当它与Date类型进行比较时,总是为false,即使是同一个时间.因此写了这个方法,用于兼容这两种类型的时间比较.
* @author slx
* @date 2009-7-13 上午10:08:52
* @modifyNote
*/
public static boolean equalsDate(Date d1, Date d2) {
if (d1 != null && d2 != null) {
return d1.getTime() == d2.getTime();
}
return false;
}
/**
* 判断后面的一天是否是前面一天的下一天
*
* @param day 基准日期
* @param nextDay 比较日期
* @return 如果比较日期是基准日期的下一天则返回true,否则为false
* @author slx
*/
public static boolean isNextDay(Date day, Date nextDay) {
return (getBetweenDays(day, nextDay) == -1);
}
/**
* 判断两个日期是否是同一天
*
* @param day
* @param otherDay
* @author slx
*/
public static boolean isSameDayxxxxxxxx(Date day, Date otherDay) {
return (getBetweenDays(day, otherDay) == 0);
}
/**
* 计算两个日期相差的天数.不满24小时不算做一天
*
* @param fDate 日期1
* @param sDate 日期2
* @return 日期1 - 日期2 的差
* @author slx
* @date 2009-7-10 下午03:15:54
* @modifyNote
*/
public static int getBetweenDays(Date fDate, Date sDate) {
return (int) ((fDate.getTime() - sDate.getTime()) / 86400000L);
}
/**
* 计算两个日期相差的天数.不满24小时不算做一天
*
* @param fDate
* @param sDate
* @return
* @throws SystemException
*/
public static int getBetweenDays(Integer fDate, Integer sDate) throws SystemException {
Date coutDate = new Date();
Date cinDate = new Date();
try {
cinDate = DateUtil2.parseToDate(fDate.toString(), "yyyyMMdd");
} catch (Exception e) {
logger.error("转换开始时间出错", e);
throw new SystemException("转换开始时间出错");
}
try {
coutDate = DateUtil2.parseToDate(sDate.toString(), "yyyyMMdd");
} catch (Exception e) {
logger.error("转换结束时间出错", e);
throw new SystemException("转换结束时间出错");
}
return (int) ((coutDate.getTime() - cinDate.getTime()) / 86400000L);
}
/**
* 日期相加指定年
*
* @param date 日期
* @param addYears 要添加的年数
* @return 相加后的日期
* @author slx
* @date 2009-9-10 上午10:26:22
* @modifyNote
*/
public static Date addYears(Date date, int addYears) {
Calendar calender = Calendar.getInstance();
calender.setTime(date);
calender.add(Calendar.YEAR, addYears);
return calender.getTime();
}
/**
* 加指定月
*
* @param date 日期
* @param addMonths 月数
* @return 相加后的日期
* @author slx
* @date 2009-9-10 上午10:26:57
* @modifyNote
*/
public static Date addMonth(Date date, int addMonths) {
Calendar calender = Calendar.getInstance();
calender.setTime(date);
calender.add(Calendar.MONTH, addMonths);
return calender.getTime();
}
/**
* 加指定天数
*
* @param date 日期
* @param addDays 天数
* @return 相加后的日期
* @author slx
* @date 2009-9-10 上午10:27:22
* @modifyNote
*/
public static Date addDay(Date date, int addDays) {
Calendar calender = Calendar.getInstance();
calender.setTime(date);
calender.add(Calendar.DAY_OF_YEAR, addDays);
return calender.getTime();
}
/**
* 加指定小时
*
* @param date
* @param addHours
* @return
*/
public static Date addHour(Date date, int addHours) {
Calendar calender = Calendar.getInstance();
calender.setTime(date);
calender.add(Calendar.HOUR, addHours);
return calender.getTime();
}
/**
* 加指定分钟
*
* @param date
* @param addMinutes
* @return
*/
public static Date addMinute(Date date, int addMinutes) {
Calendar calender = Calendar.getInstance();
calender.setTime(date);
calender.add(Calendar.MINUTE, addMinutes);
return calender.getTime();
}
/**
* 得到一年的第一天
*
* @param year 年
* @return 一年的第一天
* @author slx
* @date 2009-9-10 上午11:14:23
* @modifyNote
*/
public static Date getFirstDateOfYear(int year) {
Calendar calender = Calendar.getInstance();
calender.set(Calendar.YEAR, year);
calender.set(Calendar.DAY_OF_YEAR, calender.getActualMinimum(Calendar.DAY_OF_YEAR));
setStartTimeOfDay(calender);
return calender.getTime();
}
/**
* 得到一年的最后一天
*
* @param year 年
* @return 一年的最后一天
* @author slx
* @date 2009-9-10 上午11:14:42
* @modifyNote
*/
public static Date getLastDateOfYear(int year) {
Calendar calender = Calendar.getInstance();
calender.set(Calendar.YEAR, year);
calender.set(Calendar.DAY_OF_YEAR, calender.getActualMaximum(Calendar.DAY_OF_YEAR));
setEndTimeOfDay(calender);
return calender.getTime();
}
/**
* 判断当前日期是否是所在月份的最后一天
*
* @param date 日期
* @return 是最后一天为 true
* @author slx
* @date 2009-9-10 上午10:54:36
* @modifyNote
*/
public static boolean isLastDayOfMonth(Date date) {
Calendar calender = Calendar.getInstance();
calender.setTime(date);
int day = calender.get(Calendar.DAY_OF_MONTH);
int lastDay = calender.getActualMaximum(Calendar.DAY_OF_MONTH);
return day == lastDay;
}
/**
* 得到指定月的最后一天
*
* @param year 年
* @param month 月
* @return 最后一天
* @author slx
* @date 2009-9-10 上午11:09:56
* @modifyNote
*/
public static Date getLastDayOfMonth(int year, int month) {
Calendar calender = Calendar.getInstance();
calender.set(year, month - 1, 1);
calender.set(Calendar.DAY_OF_MONTH, calender.getActualMaximum(Calendar.DAY_OF_MONTH));
setEndTimeOfDay(calender);
return calender.getTime();
}
/**
* 得到日期所在月的最后一天
*
* @param date 日期
* @return 所在月的最后一天
* @author slx
* @date 2009-9-10 上午10:54:25
* @modifyNote
*/
public static Date getLastDayOfMonth(Date date) {
Calendar calender = Calendar.getInstance();
calender.setTime(date);
calender.set(Calendar.DAY_OF_MONTH, calender.getActualMaximum(Calendar.DAY_OF_MONTH));
setEndTimeOfDay(calender);
return calender.getTime();
}
/**
* 设置到当前月的最后时刻
*
* @param calender
* @author slx
* @date 2010-10-18 上午11:04:56
* @modifyNote
*/
private static void setEndTimeOfDay(Calendar calender) {
calender.set(Calendar.HOUR_OF_DAY, calender.getActualMaximum(Calendar.HOUR_OF_DAY));
calender.set(Calendar.MINUTE, calender.getActualMaximum(Calendar.MINUTE));
calender.set(Calendar.SECOND, calender.getActualMaximum(Calendar.SECOND));
calender.set(Calendar.MILLISECOND, calender.getActualMaximum(Calendar.MILLISECOND));
}
/**
* 得到指定月的第一天
*
* @param year 年
* @param month 月
* @return 第一天
* @author slx
* @date 2009-9-10 上午11:09:56
* @modifyNote
*/
public static Date getFirstDayOfMonth(int year, int month) {
Calendar calender = Calendar.getInstance();
calender.set(year, month - 1, 1);
calender.set(Calendar.DAY_OF_MONTH, calender.getActualMinimum(Calendar.DAY_OF_MONTH));
setStartTimeOfDay(calender);
return calender.getTime();
}
/**
* 得到指定日期所在月的第一天
*
* @param date 日期
* @return 第一天
* @author slx
* @date 2009-9-10 上午11:09:56
* @modifyNote
*/
public static Date getFirstDayOfMonth(Date date) {
Calendar calender = Calendar.getInstance();
calender.setTime(date);
calender.set(Calendar.DAY_OF_MONTH, calender.getActualMinimum(Calendar.DAY_OF_MONTH));
setStartTimeOfDay(calender);
return calender.getTime();
}
/**
* 设置到月份开始的时刻
*
* @param calender
* @author slx
* @date 2010-10-18 上午11:06:12
* @modifyNote
*/
private static void setStartTimeOfDay(Calendar calender) {
calender.set(Calendar.HOUR_OF_DAY, calender.getActualMinimum(Calendar.HOUR_OF_DAY));
calender.set(Calendar.MINUTE, calender.getActualMinimum(Calendar.MINUTE));
calender.set(Calendar.SECOND, calender.getActualMinimum(Calendar.SECOND));
calender.set(Calendar.MILLISECOND, calender.getActualMinimum(Calendar.MILLISECOND));
}
public static Date getStartTimeOfDay(Date date) {
Calendar calender = Calendar.getInstance();
calender.setTime(date);
setStartTimeOfDay(calender);
return calender.getTime();
}
public static Date getEndTimeOfDay(Date date) {
Calendar calender = Calendar.getInstance();
calender.setTime(date);
setEndTimeOfDay(calender);
return calender.getTime();
}
/**
* 得到当前年月
*
* @return 格式:2008-11
* @throws ParseException
* @author yongtree
* @date 2008-11-22 上午11:25:24
*/
public static String getThisYearMonth() {
return getYearMonth(new Date());
}
/**
* 得到年月
*
* @return 格式:2008-11
* @throws ParseException
* @author slx
* @date 2010年4月16日13:09:23
*/
public static String getYearMonth(Date date) {
Calendar today = Calendar.getInstance();
today.setTime(date);
return (today.get(Calendar.YEAR)) + "-" + ((today.get(Calendar.MONTH) + 1) >= 10 ? (today.get(Calendar.MONTH) + 1) : ("0" + (today.get(Calendar.MONTH) + 1)));
}
public static String getYear() {
Calendar today = Calendar.getInstance();
today.setTime(new Date());
return String.valueOf(today.get(Calendar.YEAR));
}
public static String getMonth() {
Calendar today = Calendar.getInstance();
today.setTime(new Date());
return String.valueOf(today.get(Calendar.MONTH) + 1);
}
public static String getDate() {
Calendar today = Calendar.getInstance();
today.setTime(new Date());
return String.valueOf(today.get(Calendar.DATE));
}
/**
* 计算两个日期之间相差的月份数
*
日期顺序不分先后不会返回负数
*
不足一个月不算做一个月
*
* @param date1 日期1
* @param date2 日期2
* @return 月数
* @author slx
* @date 2010年4月16日11:32:51
* @modifyNote
*/
public static int getBetweenMonths(Date date1, Date date2) {
int iMonth = 0;
int flag = 0;
Calendar objCalendarDate1 = Calendar.getInstance();
objCalendarDate1.setTime(date1);
Calendar objCalendarDate2 = Calendar.getInstance();
objCalendarDate2.setTime(date2);
if (objCalendarDate2.equals(objCalendarDate1)) {
return 0;
}
if (objCalendarDate1.after(objCalendarDate2)) {
Calendar temp = objCalendarDate1;
objCalendarDate1 = objCalendarDate2;
objCalendarDate2 = temp;
}
if (objCalendarDate2.get(Calendar.DAY_OF_MONTH) < objCalendarDate1.get(Calendar.DAY_OF_MONTH)) {
flag = 1;
}
if (objCalendarDate2.get(Calendar.YEAR) > objCalendarDate1.get(Calendar.YEAR)) {
iMonth = ((objCalendarDate2.get(Calendar.YEAR) - objCalendarDate1.get(Calendar.YEAR))
* 12 + objCalendarDate2.get(Calendar.MONTH) - flag)
- objCalendarDate1.get(Calendar.MONTH);
} else {
iMonth = objCalendarDate2.get(Calendar.MONTH)
- objCalendarDate1.get(Calendar.MONTH) - flag;
}
return iMonth;
}
/**
* 计算两个日期之间相差的年份数
*
日期顺序不分先后不会返回负数
*
不足一个年不算做一个年
*
* @param date1 日期1
* @param date2 日期2
* @return 年数
* @author slx
* @date 2010年4月16日12:01:46
* @modifyNote
*/
public static int getBetweenYears(Date date1, Date date2) {
return getBetweenMonths(date1, date2) / 12;
}
public static boolean before(Date date1, Date date2) {
if (date1 == null
|| date2 == null) {
return false;
}
Calendar c1 = new GregorianCalendar();
c1.setTime(date1);
Calendar c2 = new GregorianCalendar();
c2.setTime(date2);
return c1.before(c2);
}
public static boolean after(Date date1, Date date2) {
if (date1 == null
|| date2 == null) {
return false;
}
Calendar c1 = new GregorianCalendar();
c1.setTime(date1);
Calendar c2 = new GregorianCalendar();
c2.setTime(date2);
return c1.after(c2);
}
/**
* 当前时间是否失效
*
* @param expiresDate
* @return
*/
public static boolean isExpires(Date expiresDate) {
return after(new Date(), expiresDate);
}
/**
* 是否同一天
*
* @param date1
* @param date2
* @return
*/
public static boolean isSameDate(Date date1, Date date2) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
boolean isSameYear = cal1.get(Calendar.YEAR) == cal2
.get(Calendar.YEAR);
boolean isSameMonth = isSameYear
&& cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH);
boolean isSameDate = isSameMonth
&& cal1.get(Calendar.DAY_OF_MONTH) == cal2
.get(Calendar.DAY_OF_MONTH);
return isSameDate;
}
/**
* 判断两个日期是否相差一天
*
* @return
*/
public static boolean isYesterday(Date oldDate, Date newDate) {
Calendar oldCal = Calendar.getInstance();
Calendar newCal = Calendar.getInstance();
oldCal.setTime(oldDate);
newCal.setTime(newDate);
return Math.abs(newCal.get(Calendar.DAY_OF_YEAR) - oldCal.get(Calendar.DAY_OF_YEAR)) == 1;
}
/**
* 校验日期格式是否合法
*
* @param date
* @param format
* @return
*/
public static boolean isValidDate(String date, String format) {
boolean convertSuccess = true;
// 指定日期格式为四位年/两位月份/两位日期,注意yyyy/MM/dd区分大小写;
SimpleDateFormat sdf = new SimpleDateFormat(format);
try {
// 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期,比如2007/02/29会被接受,并转换成2007/03/01
sdf.setLenient(false);
sdf.parse(date);
} catch (ParseException e) {
// e.printStackTrace();
// 如果throw java.text.ParseException或者NullPointerException,就说明格式不对
convertSuccess = false;
}
return convertSuccess;
}
public static Integer getInt8Value(String date, String pattern) throws ParseException {
Date d = DateUtil2.parse(date, pattern);
return getInt8Value(d);
}
public static Integer getInt8Value(Date date) {
String year = getIntYear(date).toString();
String month = getIntMonth(date).toString();
String date1 = getIntDate(date).toString();
if (month.length() < 2) {
month = "0" + month;
}
if (date1.length() < 2) {
date1 = "0" + date1;
}
return Integer.parseInt(year + month + date1);
}
public static Integer getIntYear(Date date) {
Calendar today = Calendar.getInstance();
today.setTime(date);
return today.get(Calendar.YEAR);
}
public static Integer getIntMonth(Date date) {
Calendar today = Calendar.getInstance();
today.setTime(date);
return today.get(Calendar.MONTH) + 1;
}
public static Integer getIntDate(Date date) {
Calendar today = Calendar.getInstance();
today.setTime(date);
return today.get(Calendar.DATE);
}
public static String getStringDate(Integer date) {
String newDate = null;
if (date.toString().length() == 8) {
newDate = date.toString().substring(0, 4) + "-" + date.toString().substring(4, 6) + "-" + date.toString().substring(6, 8);
}
return newDate;
}
public final static int compareDate(String stringValue1, Date date2)
throws ParseException {
Date date1 = tryParse(stringValue1);
if (date1 == null) {
throw new ParseException("Can not parse " + stringValue1
+ " to Date.", 0);
}
if (date2 == null) {
throw new ParseException("Can not parse " + stringValue1
+ " to Date.", 0);
}
return date1.compareTo(date2);
}
public final static int compareDate(String stringValue1, String stringValue2)
throws ParseException {
Date date1 = tryParse(stringValue1);
if (date1 == null) {
throw new ParseException("Can not parse " + stringValue1
+ " to Date.", 0);
}
Date date2 = tryParse(stringValue2);
if (date2 == null) {
throw new ParseException("Can not parse " + stringValue1
+ " to Date.", 0);
}
return date1.compareTo(date2);
}
public final static Date tryParse(String stringValue) throws ParseException {
Date date = parse(stringValue, FORMAT_DATE_YYYY_MM_DD);
if (date != null) {
return date;
}
date = parse(stringValue, FORMAT_DATE_YYYYMMDD);
if (date != null) {
return date;
}
date = parse(stringValue, FORMAT_DATE_YYYY_MM_DD_HHMMSS);
if (date != null) {
return date;
}
date = parse(stringValue, FORMAT_DATE_YYYY_MM_DD_HH_MM_SS);
if (date != null) {
return date;
}
date = parse(stringValue, FORMAT_DATE_YYYY_MM_DD_HHMM);
if (date != null) {
return date;
}
date = parse(stringValue, FORMAT_DATE_PATTERN_1);
if (date != null) {
return date;
}
date = parse(stringValue, FORMAT_DATE_PATTERN_2);
if (date != null) {
return date;
}
date = parse(stringValue, FORMAT_DATE_PATTERN_3);
if (date != null) {
return date;
}
date = parse(stringValue, FORMAT_DATE_PATTERN_4);
if (date != null) {
return date;
}
return date;
}
public final static Date parse(String stringValue, String formatPattern) throws ParseException {
return parseToDate(stringValue, formatPattern);
}
public final static Date getCurrentDate() {
return Calendar.getInstance().getTime();
}
/**
* 计算2个日期差多少年多少月多少天
*
* @param calendarBirth
* @param calendarNow
* @return
*/
public static int[] getNeturalAge(Calendar calendarBirth, Calendar calendarNow) {
int diffYears = 0, diffMonths, diffDays;
int dayOfBirth = calendarBirth.get(Calendar.DAY_OF_MONTH);
int dayOfNow = calendarNow.get(Calendar.DAY_OF_MONTH);
if (dayOfBirth <= dayOfNow) {
diffMonths = getMonthsOfAge(calendarBirth, calendarNow);
diffDays = dayOfNow - dayOfBirth;
if (diffMonths == 0) {
diffDays++;
}
} else {
if (isEndOfMonth(calendarBirth)) {
if (isEndOfMonth(calendarNow)) {
diffMonths = getMonthsOfAge(calendarBirth, calendarNow);
diffDays = 0;
} else {
calendarNow.add(Calendar.MONTH, -1);
diffMonths = getMonthsOfAge(calendarBirth, calendarNow);
diffDays = dayOfNow + 1;
}
} else {
if (isEndOfMonth(calendarNow)) {
diffMonths = getMonthsOfAge(calendarBirth, calendarNow);
diffDays = 0;
} else {
calendarNow.add(Calendar.MONTH, -1);// 上个月
diffMonths = getMonthsOfAge(calendarBirth, calendarNow);
// 获取上个月最大的一天
int maxDayOfLastMonth = calendarNow.getActualMaximum(Calendar.DAY_OF_MONTH);
if (maxDayOfLastMonth > dayOfBirth) {
diffDays = maxDayOfLastMonth - dayOfBirth + dayOfNow;
} else {
diffDays = dayOfNow;
}
}
}
}
// 计算月份时,没有考虑年
diffYears = diffMonths / 12;
diffMonths = diffMonths % 12;
return new int[]{diffYears, diffMonths, diffDays};
}
/**
* 获取两个日历的月份之差
*
* @param calendarBirth
* @param calendarNow
* @return
*/
public static int getMonthsOfAge(Calendar calendarBirth,
Calendar calendarNow) {
return (calendarNow.get(Calendar.YEAR) - calendarBirth
.get(Calendar.YEAR)) * 12 + calendarNow.get(Calendar.MONTH)
- calendarBirth.get(Calendar.MONTH);
}
/**
* 判断这一天是否是月底
*
* @param calendar
* @return
*/
public static boolean isEndOfMonth(Calendar calendar) {
int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
return dayOfMonth == calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
}
/**
* 根据开始时间和结束时间返回时间段内的时间集合
*
* @param beginDate
* @param endDate
* @return List
*/
public static List getDatesBetweenTwoDate(String beginDate, String endDate) throws ParseException {
List lDate = new ArrayList<>();
lDate.add(beginDate);//把开始时间加入集合
Date d1 = parseToDate(beginDate, DATE_PATTERN);
Date d2 = parseToDate(endDate, DATE_PATTERN);
Calendar cal = Calendar.getInstance();
//使用给定的 Date 设置此 Calendar 的时间
cal.setTime(d1);
while (true) {
//根据日历的规则,为给定的日历字段添加或减去指定的时间量
cal.add(Calendar.DAY_OF_MONTH, 1);
// 测试此日期是否在指定日期之后
if (d2.after(cal.getTime())) {
lDate.add(formatDate(cal.getTime(), DATE_PATTERN));
} else {
break;
}
}
lDate.add(endDate);//把结束时间加入集合
return lDate;
}
/**
* 根据开始时间和结束时间返回时间段内的时间集合
*
* @param beginDate
* @param endDate
* @return List
*/
public static List getDatesBetweenTwoDate(String beginDate, String endDate, String fromDatePattern, String toDatePattern) {
List lDate = new ArrayList<>();
//把开始时间加入集合
lDate.add(beginDate);
Date d1 = null;
Date d2 = null;
try {
d1 = parseToDate(beginDate, fromDatePattern);
d2 = parseToDate(endDate, fromDatePattern);
} catch (Exception e) {
e.printStackTrace();
}
Calendar cal = Calendar.getInstance();
//使用给定的 Date 设置此 Calendar 的时间
cal.setTime(d1);
while (true) {
//根据日历的规则,为给定的日历字段添加或减去指定的时间量
cal.add(Calendar.DAY_OF_MONTH, 1);
// 测试此日期是否在指定日期之后
if (d2.after(cal.getTime())) {
lDate.add(formatDate(cal.getTime(), toDatePattern));
} else {
break;
}
}
//把结束时间加入集合
lDate.add(endDate);
return lDate;
}
/**
* 计算两个日期相差多少分钟
*
* @param startTime
* @param endTime
* @return
*/
public static Long getDifferMinutes(Date startTime, Date endTime) {
long nm = 1000 * 60;
Long diff = endTime.getTime() - startTime.getTime();
Long minutes = diff / nm;
return minutes;
}
}
导入完成。
以上就是Excel导出及导入的工具代码说明,此工具类比较简单,小伙伴们可根据实际需要编写扩展更多场景及功能。
其他:转载需附本文链接及说明,尊重劳动