具体代码实现如下:
Service:
public interface ExcelService {
/**
* excel导出
* @param lists 需要写入的list
* @param response response
* @param paramsMap 表头和字段对应map key:字段 value:表头
* @param outFileName 导出的文件名 xxx.xlsx
*/
void downLoadFile(List<?> lists, HttpServletResponse response, Map<String, String> paramsMap, String outFileName);
/**
* excel导入
* @param file 文件
* @param paramsMap 表头和字段对应map key:表头 value:字段
* @param tClass 实体的class
* @param <T> 泛型
* @return
* @throws IOException
*/
<T> List<T> importFile(MultipartFile file, Map<String, String> paramsMap, Class<T> tClass) throws IOException;
}
Service-Impl:
//此处import有删减,代码中对应修改为自己的即可
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
@Service
@Slf4j
public class ExcelServiceImpl implements ExcelService {
@Override
public void downLoadFile(List<?> lists, HttpServletResponse response, Map<String, String> paramsMap, String outFileName) {
String ENCODING = "UTF-8";
if (lists == null || lists.isEmpty()) {
return;
}
try (ExcelWriter writer = ExcelUtil.getWriter(true);
final OutputStream output = response.getOutputStream()) {
// 通过工具类创建writer并且进行别名
assembleWriter(writer, paramsMap);
//只输出有别名的字段
writer.setOnlyAlias(true);
// 准备将对象写入我们的 List
writer.write(lists, true);
// 获取我们的输出流
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + outFileName + ";filename*=utf-8''"
+ URLEncoder.encode(outFileName, ENCODING));
writer.flush(output, true);
} catch (Exception e) {
log.error("用户导出失败:", e);
}
}
/**
* 导出时表头工具类
* @param writer
* @param paramsMap
*/
private void assembleWriter(ExcelWriter writer, Map<String, String> paramsMap) {
/**
* 例子:writer.addHeaderAlias("username", "用户名");
* key:字段 value:表头
*/
for(Map.Entry<String, String> entry : paramsMap.entrySet()){
writer.addHeaderAlias(entry.getKey(), entry.getValue());
}
}
@Override
public <T> List<T> importFile(MultipartFile file, Map<String, String> paramsMap, Class<T> tClass) throws IOException {
String fileName = file.getOriginalFilename();
// 上传文件为空
if (StringUtils.isEmpty(fileName)) {
log.error( "没有导入文件");
}
//上传文件大小上限为10M
if (file.getSize() > ImportFileConstants.FILE_SIZE) {
log.error("文件大小超过10M");
throw new CrmException(CrmExceptionCode.FILE_SIZE_ERROR);
}
// 上传文件名格式不正确
if (fileName.lastIndexOf(".") != -1 && !".xlsx".equals(fileName.substring(fileName.lastIndexOf(".")))) {
log.error( "文件名格式不正确, 请使用后缀名为.xlsx的文件");
}
try(InputStream inputStream = file.getInputStream();
ExcelReader excelReader = ExcelUtil.getReader(inputStream, "sheet1")) {
assembleReader(excelReader, paramsMap);
List<T> t = excelReader.readAll(tClass);
if (t.size() < 1 || t.size() > ImportFileConstants.FILE_NUM){
throw new CrmException(CrmExceptionCode.FILE_NUM_ERROR);
}
return t;
}catch (Exception e){
log.error("上传文件出错"+e);
throw new CrmException(CrmExceptionCode.FILE_NUM_ERROR);
}
}
/**
* 导入时表头工具类
* @param reader
*/
private void assembleReader(ExcelReader reader, Map<String, String> paramsMap) {
/**
* 例子:reader.addHeaderAlias("用户名", "username");
* key:表头 value:字段
*/
for(Map.Entry<String, String> entry : paramsMap.entrySet()){
reader.addHeaderAlias(entry.getKey(), entry.getValue());
}
}
}
扩展:
- T 泛型和 ? 通配符的区别?
- 泛型代表了所有Java类型中的一个(一旦声明成一种类型,则完全受这种类型约束,也就是说在运行时会将T替换成一种具体的数据类型);而通配符代表的是所有的Java类型(通配符不是代表具体某种数据类型,而是通用于所有的数据类型)
- 泛型可以进行写操作,但是通配符不行(因为通配符可代表任何的数据类型,所以在写时会因为不知道是什么类型而无法写入)
- 泛型在获取泛指值时可以使用Object或者T来承接;通配符则只可以使用Object来承接
- 使用extends限定类型子集的时候,泛型可以多继承,通配符则不行
- 使用super限定父集的时候,通配符是可以限定父集的,但是泛型是不可以的