一、引入jar
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.8</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.8</version>
</dependency>
二.swagger常用注解
1、与实体相关的注解
@ApiModel:用在实体类上,对实体类做注释(value:字符串,模型的简短别名,使得在文档的导航中便于识别;description:字符串,模型的附加描述)
@ApiModelProperty:用在属性上,对属性做注释
2、与接口相关的注解
@Api:用在controller上,对controller进行注释;
@ApiOperation:用在API方法上,对该API做注释,说明API的作用;
@ApiParam 作用在接口方法上,描述单个参数信息,属性基本与@ApiImplicitParam一样,但可以作用在方法、参数、属性上;
@ApiImplicitParams:用来包含API的一组参数注解,可以简单的理解为参数注解的集合声明;
@ApiImplicitParam:用在@ApiImplicitParams注解中,也可以单独使用,说明一个请求参数的各个方面,该注解包含的常用选项有:
paramType:参数所放置的地方,包含query、header、path、body以及form,最常用的是前四个。
name:参数名;
dataType:参数类型,可以是基础数据类型,也可以是一个class;
required:参数是否必须传;
value:参数的注释,说明参数的意义;
defaultValue:参数的默认值;
@ApiResponses:通常用来包含接口的一组响应注解,可以简单的理解为响应注解的集合声明;
@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
code:即httpCode,例如400
message:信息,例如"请求参数没填好"
几个注意点:
为了在swagger-ui上看到输出,至少需要两个注解:@Api和@ApiOperation
即使只有一个@ApiResponse,也需要使用@ApiResponses包住
对于@ApiImplicitParam的paramType:query、form域中的值需要使用@RequestParam获取, header域中的值需要使用@RequestHeader来获取,path域中的值需要使用@PathVariable来获取,body域中的值使用@RequestBody来获取,否则可能出错;而且如果paramType是body,name就不能是body,否则有问题,与官方文档中的“If paramType is "body", the name should be "body"不符。
三.lombok常用注解
1.setter、getter方法
@Data
2.所有参数构造器
@AllArgsConstructor
3.无参数的构造器
@NoArgsConstructor
4.重写toSting方法(将父类中的属性也算到tostring中)
@ToString(callSuper = true)
5.重写equalsAndhashCode方法(若为true将父类中的属性也算到tostring中)
@EqualsAndHashCode(callSuper = false)
6.日志
@Slf4j : 注解在类上, 为类提供一个属性名为 log 的 log4j 的日志对象
@Log4j : 注解在类上, 为类提供一个属性名为 log 的 log4j 的日志对象
四.easyExcel注解
类注解
1.标题样式
@HeadStyle
参数 含义
dataFormat 日期格式
hidden 设置单元格使用此样式隐藏
locked 设置单元格使用此样式锁定
quotePrefix 在单元格前面增加`符号,数字或公式将以字符串形式展示
horizontalAlignment 设置是否水平居中
wrapped 设置文本是否应换行。将此标志设置为true通过在多行上显示使单元格中的所有内容可见
verticalAlignment 设置是否垂直居中
rotation 设置单元格中文本旋转角度。03版本的Excel旋转角度区间为-90°90°,07版本的Excel旋转角度区间为0°180°
indent 设置单元格中缩进文本的空格数
borderLeft 设置左边框的样式
borderRight 设置右边框样式
borderTop 设置上边框样式
borderBottom 设置下边框样式
leftBorderColor 设置左边框颜色
rightBorderColor 设置右边框颜色
topBorderColor 设置上边框颜色
bottomBorderColor 设置下边框颜色
fillPatternType 设置填充类型
fillBackgroundColor 设置背景色
fillForegroundColor 设置前景色
shrinkToFit 设置自动单元格自动大小
2.标题高度
@HeadRowHeight(value = 15)
3.标题字体格式
@HeadFontStyle
参数 含义
fontName 设置字体名称
fontHeightInPoints 设置字体高度
italic 设置字体是否斜体
strikeout 是否设置删除线
color 设置字体颜色
typeOffset 设置偏移量
underline 设置下划线
charset 设置字体编码
bold 设置字体是否加粗
4.文本样式
@ContentStyle
参数 含义
dataFormat 日期格式
hidden 设置单元格使用此样式隐藏
locked 设置单元格使用此样式锁定
quotePrefix 在单元格前面增加`符号,数字或公式将以字符串形式展示
horizontalAlignment 设置是否水平居中
wrapped 设置文本是否应换行。将此标志设置为true通过在多行上显示使单元格中的所有内容可见
verticalAlignment 设置是否垂直居中
rotation 设置单元格中文本旋转角度。03版本的Excel旋转角度区间为-90°90°,07版本的Excel旋转角度区间为0°180°
indent 设置单元格中缩进文本的空格数
borderLeft 设置左边框的样式
borderRight 设置右边框样式
borderTop 设置上边框样式
borderBottom 设置下边框样式
leftBorderColor 设置左边框颜色
rightBorderColor 设置右边框颜色
topBorderColor 设置上边框颜色
bottomBorderColor 设置下边框颜色
fillPatternType 设置填充类型
fillBackgroundColor 设置背景色
fillForegroundColor 设置前景色
shrinkToFit 设置自动单元格自动大小
5.文本行高度
@ContentRowHeight(value = 15)
6.文本字体样式
@ContentFontStyle
参数 含义
fontName 字体名称
fontHeightInPoints 字体高度
italic 是否斜体
strikeout 是否设置删除水平线
color 字体颜色
typeOffset 偏移量
underline 下划线
bold 是否加粗
charset 编码格式
7.列宽度-常用注解
@ColumnWidth(30)
8.忽略未注解-不导出
@ExcelIgnoreUnannotated
9.文本合并
@OnceAbsoluteMerge
firstRowIndex // 初始行
lastRowIndex // 最后一行
firstColumnIndex // 初始列
lastColumnIndex // 最后一列
属性注解
10.每列设置-常用注解
@ExcelProperty
参数 含义
value 列名称
index 列序号(index比order优先)
order 列排序
converter 转换器(通常不用设置)
如:@ExcelProperty(value = "性别", order = 4, index = 0, converter = SexConverter.class)性别转换器需自定义,详情见如下第四部分示例
11.忽略项-不导出
ExcelIgnore
12.列宽度
@ColumnWidth(60)
13.文本合并
@ContentLoopMerge
eachRow // 合并行
columnExtend // 合并列
五.实例演示
1.性别转换器SexConverter(可选择性需要)
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class SexConverter implements Converter<Integer> {
@Override
public Class supportJavaTypeKey() {
return Integer.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public Integer convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
return "男".equals(cellData.getStringValue()) ? 1 : 0;
}
@Override
public CellData convertToExcelData(Integer value, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
return new CellData(value.equals(1) ? "男" : "女");
}
}
2.PersonDTO
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.*;
import io.swagger.annotations.ApiModel;
import lombok.*;
@ApiModel("导出业务对象")
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@HeadStyle(wrapped = false,fillForegroundColor = 13)
@HeadFontStyle(fontHeightInPoints = 10)
@ColumnWidth(30)
public class PersonDTO {
@ExcelProperty(value = "工号", order = 1) // 列名,列排序-常用注解
String num;
@ExcelProperty(value = "姓名", order = 2)
String name;
@ExcelProperty(value = "年龄", order = 3)
int age;
@ExcelProperty(value = "性别", order = 4, index = 0, converter = SexConverter.class) // 列名,列排序,列序号,数据转换方式。如果index和order都定义,以index为准,通常不用设置converter
@ColumnWidth(60)
int sex;
@ExcelIgnore // 忽略项-不导出
long id;
}
3.Excel导入监听器(可选择性需要)
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.ArrayList;
import java.util.List;
public class ExcelListener extends AnalysisEventListener<PersonDTO> {
// 读取数据初始化值
private static final int BATCH_COUNT = 50;
List<PersonDTO> list = new ArrayList<PersonDTO>();
@Override
public void invoke(PersonDTO personDTO, AnalysisContext analysisContext) {
list.add(personDTO);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
if (list.size() == 0) {
return;
}
saveData();
System.out.println("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
public void saveData() {
System.out.println(list);
}
}
4.测试类Test
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
public class Test {
public static void main(String[] args) throws Exception {
System.out.println("test");
log.error("log-test");
List<PersonDTO> persons = new ArrayList<>();
PersonDTO personOne = new PersonDTO();
personOne.setAge(1);
personOne.setName("Linsa");
personOne.setNum("111");
personOne.setSex(1);
persons.add(personOne);
PersonDTO personTwo = new PersonDTO();
personTwo.setAge(18);
personTwo.setName("Rose");
personTwo.setNum("222");
personTwo.setSex(2);
persons.add(personTwo);
// 获取临时目录
String tempdir = "D:\\tmp\\";
String fileNameOne = "One_文件.xlsx";
String fileNameTwo = "Two_文件.xlsx";
File writerFileOne = new File(tempdir, fileNameOne);
writerFileOne.createNewFile();
File writerFileTwo = new File(tempdir, fileNameTwo);
writerFileTwo.createNewFile();
// 导出Excel
EasyExcel.write(writerFileOne).head(PersonDTO.class).sheet("sheet1").doWrite(persons);
// 导入Excel
EasyExcel.read(writerFileOne, PersonDTO.class, new ExcelListener()).sheet().doRead();
// 导出Excel
writeExcel(writerFileTwo, persons.get(0), persons);
// 导入Excel
readExcel(writerFileTwo);
}
private static void writeExcel(File writerFile, PersonDTO person, List<PersonDTO> persons) {
ExcelWriter excelWriter = EasyExcel.write(writerFile).build();
WriteSheet sheet1 = EasyExcel.writerSheet(0, "sheet1")
.head(PersonDTO.class).build();
WriteSheet sheet2 = EasyExcel.writerSheet(1, "sheet2")
.head(PersonDTO.class).build();
excelWriter.write(Arrays.asList(person), sheet1);
excelWriter.write(persons, sheet2);
excelWriter.finish(); // 写excel结束
}
private static void readExcel(File writerFile) {
String sheetName = EasyExcel.read(writerFile).build().excelExecutor().sheetList().get(0).getSheetName();
System.out.println("Excel名字:" + sheetName);
// headRowNumber(1)-Excel从第几行开始读
List<PersonDTO> listOne = EasyExcel.read(writerFile).head(PersonDTO.class).sheet(0).headRowNumber(1).doReadSync();
System.out.println("sheet1数据:" + listOne);
List<PersonDTO> listTwo = EasyExcel.read(writerFile).head(PersonDTO.class).sheet(1).headRowNumber(1).doReadSync();
System.out.println("sheet2数据:" + listTwo);
}
}