当前位置: 首页 > 编程笔记 >

java springboot poi 从controller 接收不同类型excel 文件处理

赵锐
2023-03-14
本文向大家介绍java springboot poi 从controller 接收不同类型excel 文件处理,包括了java springboot poi 从controller 接收不同类型excel 文件处理的使用技巧和注意事项,需要的朋友参考一下

根据poi接收controller层的excel文件导入

       可使用后缀名xls或xlsx格式的excel。

1.pom引入

    <!-- poi 操作Excel -->
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi</artifactId>
      <version>3.17</version>
    </dependency>
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>3.17</version>
    </dependency>

2.ExcelImportUtil 工具类创建 

import com.guard.biz.common.util.excel.ExcelIn;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author Wei
 * @time 2019/10/29
 * @Description excel 导入工具类
 */
public class ExcelImportUtil<T> {
  private static final Logger log = LoggerFactory.getLogger(ExcelImportUtil.class);
  private static BeanUtilsBean beanUtilsBean = new BeanUtilsBean();
  static {
    beanUtilsBean.getConvertUtils().register(new org.apache.commons.beanutils.converters.DateConverter(null), java.util.Date.class);
  }
  /**
   * 表头名字和对应所在第几列的下标,用于根据title取到对应的值
   */
  private final Map<String, Integer> title_to_index = new HashMap<>();
  /**
   * 所有带有ExcelIn注解的字段
   */
  private final List<Field> fields = new ArrayList<>();
  /**
   * 统计表格的行和列数量用来遍历表格
   */
  private int firstCellNum = 0;
  private int lastCellNum = 0;
  private int firstRowNum = 0;
  private int lastRowNum = 0;
  private String sheetName;
  private Sheet sheet;
  public List<T> read(InputStream in, Class clazz) throws Exception {
    gatherAnnotationFields(clazz);
    configSheet(in);
    configHeader();
    List rList = null;
    try {
      rList = readContent(clazz);
    } catch (IllegalAccessException e) {
      throw new Exception(e);
    } catch (InstantiationException e) {
      throw new Exception(e);
    } catch (InvocationTargetException e) {
      throw new Exception(e);
    }
    return rList;
  }
  private List readContent(Class clazz) throws IllegalAccessException, InstantiationException, InvocationTargetException {
    Object o = null;
    Row row = null;
    List<Object> rsList = new ArrayList<>();
    Object value = null;
    for (int i = (firstRowNum + 1); i <= lastRowNum; i++) {
      o = clazz.newInstance();
      row = sheet.getRow(i);
      Cell cell = null;
      for (Field field : fields) {
        //根据注解中的title,取到表格中该列所对应的的值
        Integer column = title_to_index.get(field.getAnnotation(ExcelIn.class).title());
        if (column == null) {
          continue;
        }
        cell = row.getCell(column);
        value = getCellValue(cell);
        if (null != value && StringUtils.isNotBlank(value.toString())) {
          beanUtilsBean.setProperty(o, field.getName(), value);
        }
      }
      rsList.add(o);
    }
    return rsList;
  }
  private void configSheet(InputStream in) throws Exception {
    // 根据文件类型来分别创建合适的Workbook对象
    try (Workbook wb = WorkbookFactory.create(in)) {
      getSheetByName(wb);
    } catch (FileNotFoundException e) {
      throw new Exception(e);
    } catch (IOException e) {
      throw new Exception(e);
    }
  }
  /**
   * 根据sheet获取对应的行列值,和表头对应的列值映射
   */
  private void configHeader() {
    this.firstRowNum = sheet.getFirstRowNum();
    this.lastRowNum = sheet.getLastRowNum();
    //第一行为表头,拿到表头对应的列值
    Row row = sheet.getRow(firstRowNum);
    this.firstCellNum = row.getFirstCellNum();
    this.lastCellNum = row.getLastCellNum();
    for (int i = firstCellNum; i < lastCellNum; i++) {
      title_to_index.put(row.getCell(i).getStringCellValue(), i);
    }
  }
  /**
   * 根据sheet名称获取sheet
   *
   * @param workbook
   * @return
   * @throws Exception
   */
  private void getSheetByName(Workbook workbook) throws Exception { 
    int sheetNumber = workbook.getNumberOfSheets();
    for (int i = 0; i < sheetNumber; i++) {
      String name = workbook.getSheetName(i);
      if (StringUtils.equals(this.sheetName, name)) {
        this.sheet = workbook.getSheetAt(i);
        return;
      }
    }
    throw new Exception("excel中未找到名称为" + this.sheetName + "的sheet");
  }
  /**
   * 根据自定义注解,获取所要导入表格的sheet名称和需要导入的字段名称
   *
   * @param clazz
   * @throws Exception
   */
  private void gatherAnnotationFields(Class clazz) throws Exception {
    if (!clazz.isAnnotationPresent(ExcelIn.class)) {
      throw new Exception(clazz.getName() + "类上没有ExcelIn注解");
    }
    ExcelIn excelIn = (ExcelIn) clazz.getAnnotation(ExcelIn.class);
    this.sheetName = excelIn.sheetName();
    // 得到所有定义字段
    Field[] allFields = FieldUtils.getAllFields(clazz);
    // 得到所有field并存放到一个list中
    for (Field field : allFields) {
      if (field.isAnnotationPresent(ExcelIn.class)) {
        fields.add(field);
      }
    }
    if (fields.isEmpty()) {
      throw new Exception(clazz.getName() + "中没有ExcelIn注解字段");
    }
  }
  private Object getCellValue(Cell cell) {
    if (cell == null) {
      return "";
    }
    Object obj = null;
    switch (cell.getCellTypeEnum()) {
      case BOOLEAN:
        obj = cell.getBooleanCellValue();
        break;
      case ERROR:
        obj = cell.getErrorCellValue();
        break;
      case FORMULA:
        try {
          obj = String.valueOf(cell.getStringCellValue());
        } catch (IllegalStateException e) {
          obj = numericToBigDecimal(cell);
        }
        break;
      case NUMERIC:
        obj = getNumericValue(cell);
        break;
      case STRING:
        String value = String.valueOf(cell.getStringCellValue());
        value = value.replace(" ", "");
        value = value.replace("\n", "");
        value = value.replace("\t", "");
        obj = value;
        break;
      default:
        break;
    }
    return obj;
  }
  private Object getNumericValue(Cell cell) {
    // 处理日期格式、时间格式
    if (HSSFDateUtil.isCellDateFormatted(cell)) {
      return cell.getDateCellValue();
    } else if (cell.getCellStyle().getDataFormat() == 58) {
      // 处理自定义日期格式:m月d日(通过判断单元格的格式id解决,id的值是58)
      double value = cell.getNumericCellValue();
      return org.apache.poi.ss.usermodel.DateUtil.getJavaDate(value);
    } else {
      return numericToBigDecimal(cell);
    }
  }
  private Object numericToBigDecimal(Cell cell) {
    String valueOf = String.valueOf(cell.getNumericCellValue());
    BigDecimal bd = new BigDecimal(valueOf);
    return bd;
  }
}

 3.ExcelIn注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * @author Lei
 * @time 2019/10/29
 * @Description
 */
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE, ElementType.FIELD})
public @interface ExcelIn {
  /**
   * 导入sheet名称
   *
   * @return
   */
  String sheetName() default "";
  /**
   * 字段对应的表头名称
   *
   * @return
   */
  String title() default "";
}

 4.创建excel中的对象

import lombok.Data;
import lombok.ToString;
import java.util.Date;
/**
 * @author Lei
 * @time 2019/10/29
 * @Description
 */
@ToString
@Data
@ExcelIn(sheetName = "用户")
public class User {
  private String id;
  @ExcelIn(title = "姓名")
  private String name;
  @ExcelIn(title = "年龄")
  private Integer age;
  @ExcelIn(title = "出生日期")
  private Date birthDate;
}

 5.controller层接收

@PostMapping("/batch/excel")
  @ApiOperation(value = "根据excel文件批量导入")
  public ResponseVO batchAddDeviceByExcelImport(MultipartFile multipartFile) {
    return new ResponseVO(deviceService.addDeviceByExcelImport(multipartFile));
  }

 6.service处理(此处仅打印)

public boolean addDeviceByExcelImport(MultipartFile multipartFile) {
    File file = null;
    try {
      file = File.createTempFile("temp", null);
    } catch (IOException e) {
      e.printStackTrace();
    }
    try {
      multipartFile.transferTo(file);
    } catch (IOException e) {
      e.printStackTrace();
    }
    file.deleteOnExit();
    InputStream inputStream = null;
    try {
      inputStream = new FileInputStream(file);
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }
    ExcelImportUtil<User> reader = new ExcelImportUtil<>();
    List<User> userList = null;
    try {
      userList = reader.read(inputStream, User.class);
    } catch (Exception e) {
      log.error(e.getMessage());
      throw new CodeException("51302", e.getMessage());
    }
      userList.stream().forEach(e -> log.info(e.toString()));
    return true;
  }

7.测试

(1)两种文件类型的excel

 (2)excel中html" target="_blank">格式如下,注意红色箭头所指的地方 对应user对象中的字段以及sheet名

 (3)swagger测试

(4)成功打印

总结

以上所述是小编给大家介绍的java springboot poi 从controller 接收不同类型excel 文件处理,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对小牛知识库网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

 类似资料:
  • 我有一个这样的 txt 文件 163钱滴24 454快乐112 45 没有你什么都没有 56 第一个数字是歌曲的id,我想将其存储为整数,第二个数字是字符串!这不是一个词!第三个是整数,它是歌曲的点赞数。我想将它们存储在一个数组中,但当我使用scanner方法时,我会逐字存储它们,当歌曲有名字时 有什么方法可以读取 txt 文件,将第一个数字存储为 int,然后扫描整个字符串(歌曲名称),直到下一

  • -对于使用注释的任何控制器,它都应以json形式返回错误响应 -应将任何其他控制器的错误消息打印到屏幕(用注释) 问题是,当我声明这两个异常处理程序时,spring总是使用,而从不使用来处理异常。 如何使这起作用?顺便说一句:我尝试使用@order注释,但这似乎不起作用。 以下是我的异常处理程序: 当我删除时,spring才正确调用(仅适用于用批注的类)....但是,当我添加时,所有操作都将通过进

  • 我需要加载不同服务器上存在的类文件,并在类文件中执行方法。我不想使用超文本传输协议或RMI,但想应用这种方法。我正在看URLClassLoader,但没有得到任何地方。有人能给我一个从不同服务器加载类的例子吗?

  • 问:如何运行一个安装文件 .reg 答:注:your.reg为文件名 ExecWait "regedit.exe /s your.reg" 问:如何运行一个安装文件 .inf 答:注:skins.inf 为文件名 ExecWait "RunDll32 advpack.dll,LaunchINFSection skins.inf,DefaultInstall" 问:如何运行一个安装文件 .msi 答

  • 问题内容: 我有一个需要从网站下载PDF的要求。PDF需要在代码中生成,我认为这将是freemarker和iText等PDF生成框架的结合。还有更好的办法吗? 但是,我的主要问题是如何允许用户通过Spring Controller下载文件? 问题答案: 一般来说,当你拥有时,你可以在其中编写任何内容。你可以将此输出流作为将生成的PDF放置到生成器的地方。另外,如果你知道要发送的文件类型,则可以设置

  • 我试图用纯文本(utf-8)处理一个POST请求,但spring似乎不喜欢调用的纯文本性质。可能是它不受支持-或者是我编码错误吗? 回应是: 已解决[org.springframework.web.httpmediatypenotsupportedException:不支持内容类型'application/x-www-form-urlencoded'] 我用curl命令进行了测试: txt包含纯文