ssm下的Excel文件处理

ssm下的Excel文件处理

3. 拓展:Excel处理

3.1 编写Excel处理的工具类:

import org.apache.poi.ss.usermodel.*;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 处理Excel的工具类
 */
public class ExcelUtil {

    //这是Excel的表头和键的映射关系
    private static final Map<String ,String> map = new HashMap<>();

    /**
     * 获取Excel的映射关系
     * @return
     */
    public static Map getExcelMap(){
        return map;
    }

    /**
     * 通过对象集合导出一个Excel表
     * @param fileName 导出之后的文件名
     * @param sizeOfSheet  一个Sheet存放的最大信息条数
     * @param dataList  集合数据
     * @param os  写入的流
     * @param <T>  集合的泛型
     */
    public static <T>void exportExcel(String fileName,
                                      int sizeOfSheet,
                                      List<T> dataList, 
                                      OutputStream os) {
        if (map.size()==0){
            System.out.println("没有设置映射关系");
            return;
        }
        //判断文件名是否复合Excel文件命名
        boolean xls = fileName.endsWith("xls");
        try {
            //利用工作簿工厂创建一个工作簿
            Workbook workbook = WorkbookFactory.create(xls);
            //根据数据条数计算出需要创建sheet数量
            int numberOfSheets;
            if(dataList.size() % sizeOfSheet == 0){
                numberOfSheets = dataList.size() / sizeOfSheet; //计算sheet数量
            } else {
                numberOfSheets = dataList.size() / sizeOfSheet + 1;//计算sheet数量
            }
            //通过循环在工作簿中创建sheet表,并且
            for (int number = 0;number<numberOfSheets;number++){
                //首先创建sheet(设置sheet的名称为sheet1~sheetN)
                Sheet sheet = workbook.createSheet("sheet"+number);
                //在sheet中创建第0行。
                Row row = sheet.createRow(0);
                //这个Map就是用来记录列号对应的属性名
                Map<Integer,String> columnsMap = new HashMap<>();
                int index = 0; //这个index的值走到最后就是最大的列数
                //在0行放置列的属性名
                for(String title: map.keySet()){
                    columnsMap.put(index, map.get(title));
                    Cell cell = row.createCell(index++);
                    cell.setCellValue(title);
                }
                //设置第一行开始写数据
                int rowIndex = 1;
                //计算当前sheet存储的数据在集合中的开始位置
                int start = number * sizeOfSheet;
                //计算当前sheet存储的数据在集合中的结束位置
                int end = (number + 1) * sizeOfSheet;

                if(end > dataList.size()) //校验最大值,不能超过集合的大小
                    end = dataList.size();

                for(int k=start; k<end; k++){
                    Row dataRow = sheet.createRow(rowIndex++);
                    T t = dataList.get(k);
                    Class<?> clazz = t.getClass();
                    for(int i=0; i<index; i++){//这个循环的目的就是为了保持与表头的列数量一致
                        Cell cell = dataRow.createCell(i); //创建数据行的单元格
                        String prop = columnsMap.get(i); //取到该列使用的属性名
                        String methodName = "get" + prop.substring(0,1).toUpperCase() + prop.substring(1);
                        Method method = clazz.getMethod(methodName);
                        Object value = method.invoke(t);
                        cell.setCellValue(value.toString());
                    }
                }
            }
            workbook.write(os);
            workbook.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过Excel表获取到对象的集合
     * @param is  读取Excel表的流
     * @param clazz 集合对象的字节码文件对象
     * @param <T> 集合的泛型
     * @return
     */
    public static <T> List<T> importExcel(InputStream is, Class<T> clazz){
        if (map.size()==0){
            System.out.println("没有设置映射关系");
            return null;
        }
        List<T> dataList = new ArrayList<>();
        try {
            //针对给定的excel文件创建一个对应的工作簿对象,这个工作簿对象中就已经包含有数据了
            Workbook workbook = WorkbookFactory.create(is);
            //不知道在哪个sheet中存放数据,因此需要一个一个的sheet查看
            int numberOfSheets = workbook.getNumberOfSheets(); //获取sheet数量
            for(int i=0; i<numberOfSheets; i++){
                Sheet sheet = workbook.getSheetAt(i); //获取给定位置的sheet
                int rows = sheet.getPhysicalNumberOfRows();//获取实际使用的行数
                if(rows <= 1) continue; //只有1行或者1行都没有 表示没有数据,直接跳过该sheet
                Row titleRow = sheet.getRow(0); //第一行表示标题行
                int cells = titleRow.getPhysicalNumberOfCells();//获取标题行实际使用的列数
                Map<Integer, String> columnsMap = new HashMap<>(); //存储单元格下标与标题
                for(int j=0; j<cells; j++){
                    Cell cell = titleRow.getCell(j); //获取给定位置的单元格
                    String title = cell.getStringCellValue(); //获取单元格内容,这里是获取字符串形式的内容
                    columnsMap.put(j, title);
                }
                //开始解析数据行
                for(int row=1; row<rows; row++){
                    T t = clazz.newInstance();
                    Row dataRow = sheet.getRow(row); //获取给定位置的数据行
                    for(int n=0; n<cells; n++){//循环行内的单元格
                        Cell cell = dataRow.getCell(n); //获取给定的位置的单元格
                        Object cellValue = null; //单元格存储内容
                        switch (cell.getCellType()){//对每一种单元格类型做出处理
                            case STRING:
                                cellValue = cell.getStringCellValue(); break;
                            case BOOLEAN:
                                cellValue = cell.getBooleanCellValue(); break;
                            case NUMERIC: //数字
                                //POI提供的工具类DateUtil可以用来判断一个单元格的类型是否是日期格式
                                if(DateUtil.isCellDateFormatted(cell)){
                                    cellValue = cell.getDateCellValue();
                                } else {
                                    cellValue = cell.getNumericCellValue();
                                }
                                break;
                            case BLANK: //空白
                                cellValue = "";
                                break;
                        }
                        String title = columnsMap.get(n); //获取该列的标题
                        String prop = map.get(title); //获取标题对应的属性
                        Field field = clazz.getDeclaredField(prop);//得到类中定义的属性字段
                        Class<?> fieldType = field.getType(); //获取字段类型
                        field.setAccessible(true);
                        field.set(t, getObject(cellValue, fieldType));
                    }
                    dataList.add(t);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataList;
    }

    /**
     * 判断
     * @param cellValue
     * @param fieldType
     * @return
     * @throws ParseException
     */
    private static Object getObject(Object cellValue, Class<?> fieldType) throws ParseException {
        if(cellValue == null) return null;
        if(fieldType == String.class){
            cellValue = cellValue.toString();
        } else if(fieldType == int.class || fieldType == Integer.class){
            cellValue = (int)Double.parseDouble(cellValue.toString());
        } else if(fieldType == short.class || fieldType == Short.class){
            cellValue = (short)Double.parseDouble(cellValue.toString());
        } else if(fieldType == byte.class || fieldType == Byte.class){
            cellValue = (byte)Double.parseDouble(cellValue.toString());
        } else if(fieldType == long.class || fieldType == Long.class){
            cellValue = (long)Double.parseDouble(cellValue.toString());
        } else if(fieldType == float.class || fieldType == Float.class){
            cellValue = Float.parseFloat(cellValue.toString());
        } else if(fieldType == double.class || fieldType == Double.class){
            cellValue = Double.parseDouble(cellValue.toString());
        } else if(fieldType == boolean.class || fieldType == Boolean.class){
            cellValue = Boolean.parseBoolean(cellValue.toString());
        } else if(fieldType == char.class || fieldType == Character.class){
            cellValue = cellValue.toString().charAt(0);
        } else if(fieldType == Date.class){
            cellValue = new SimpleDateFormat("yyyy/MM/dd").parse(cellValue.toString());
        } else if(fieldType == java.sql.Date.class){
            Date date = new SimpleDateFormat("yyyy/MM/dd").parse(cellValue.toString());
            cellValue = new java.sql.Date(date.getTime());
        } else if(fieldType == Timestamp.class){
            Date date = new SimpleDateFormat("yyyy/MM/dd").parse(cellValue.toString());
            cellValue = new Timestamp(date.getTime());
        }
        return cellValue;
    }
}

3.2 测试方法:

@Test
public void test() throws SQLException {
    //1. 必须先设置对象和Excel表的映射关系,key为Excel表中的表头,value为对应属性名。
    Map excelMap = ExcelUtil.getExcelMap();
    excelMap.put("小区名","name");
    excelMap.put("小区地址","address");
    excelMap.put("小区面积","area");
    excelMap.put("小区绿化","green");
    excelMap.put("小区物业","property");
    
    //2.1 对集合生成Excel表进行测试
    //2.1.1 获取需要生成Excel表的集合(这是通过持久层方法从数据库中获取的小区对象信息的集合)
    List<Community> list = communityDao.showCommunities(new CommunityCondition(null,null,1,10));
    //2.1.2 将调用方法传递参数
    try {
        ExcelUtil.exportExcel("D:\\Excel\\1.xls",10,list,new FileOutputStream("D:\\Excel\\1.xls"));
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    
    //2.2 对Excel表生成集合对象进行测试
    try {
        //调用方法返回一个对应泛型的集合
        List<Community> communities = ExcelUtil.importExcel(new FileInputStream("D:\\Excel\\1.xls"), Community.class);
        communities.forEach(System.out::println);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
}

3.3 在ssm中的运用

3.3.1 示例:下载小区信息

点击下载小区信息,实现小区信息从数据库中读取并写入Excel文件。

注:下面的代码最好写在service层中,返回一个data数据即可,这里只是简单演示

@GetMapping("/downloadExcel")
private ResponseEntity<byte[]> downloadExcel(@RequestHeader("User-Agent") String userAgent) throws IOException {
    List<CommunityModel> list = communityService.getCommunities("小区");
    Map excelMap = ExcelUtil.getExcelMap();
    excelMap.put("ID","id");
    excelMap.put("小区名","name");
    //这里可以从配置文件中读取,也可以自己定义。
    String fileName = "D:\\Excel\\2.xls";
    
    File downloadFile = new File(fileName);
    FileOutputStream fileOutputStream = new FileOutputStream(downloadFile);
    ExcelUtil.exportExcel(fileName,20,list,fileOutputStream);

    byte[] data = FileUtils.readFileToByteArray(downloadFile);
    //解决ie下载时文件名乱码的问题
    userAgent = userAgent.toUpperCase();
    //判断是否是ie浏览器
    if (userAgent.contains("MSIE") || userAgent.contains("TRIDENT") || userAgent.contains("EDGE")) {
        //IE下载文件名乱码可以直接通过URL编码解决
        fileName = URLEncoder.encode(fileName, "UTF-8"); //StandardCharsets.UTF_8.name();
    }else{
        //其他浏览器需要使用转码进行解决
        fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
    }
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Type", MediaType.APPLICATION_OCTET_STREAM_VALUE);
    headers.add("Content-Disposition", "attachment; filename=" + fileName);
    return new ResponseEntity<>(data, headers, HttpStatus.OK);

}
3.3.2 示例:导入小区信息

controller层:

@PostMapping("/import")
public int importCommunities(@RequestPart(name = "file") MultipartFile file){
    Map excelMap = ExcelUtil.getExcelMap();
    excelMap.put("小区名","name");
    excelMap.put("小区地址","address");
    excelMap.put("小区面积","area");
    excelMap.put("小区绿化","green");
    excelMap.put("小区物业","property");
    try {
        InputStream inputStream = file.getInputStream();
        List<Community> communities = ExcelUtil.importExcel(inputStream, Community.class);
        int result = communityService.importCommunity(communities);
        return result;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return -1;
}

service层:

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, rollbackFor = Exception.class)
@Override
public int importCommunity(List<Community> communities) {//思考,集合过大,怎么操作?
    //假设一次导入1000条
    int times = communities.size() % 1000 == 0 ? communities.size() / 1000 : communities.size() / 1000 + 1;
    int result = 0;
    for(int i=0; i<times; i++){
        int start = i * 1000;
        int end = (i + 1) * 1000;
        if(end > communities.size())
            end = communities.size();
        List<Community> subList = communities.subList(start, end);
        result += communityMapper.importCommunity(subList);
    }
    return result == communities.size() ? 1 : 0;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值