简单导入导出

 依赖管理

        <!--  POI依赖  -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version> 5.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version> 5.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.17.0</version> <!-- 确保这里是支持 atTrace() 的版本 -->
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.17.0</version> <!-- 保持 API 和 core 版本一致 -->
        </dependency>

实体类使用注解

package satellite.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD) // 应用于字段
@Retention(RetentionPolicy.RUNTIME) // 在运行时可用
public @interface CsvHeader {
    int index();
    String header(); // 存储字段的中文名称
    String fieldType() default "String";
}

工具类

package satellite.util;

import org.apache.poi.ss.usermodel.*;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import satellite.annotation.CsvHeader;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Comparator;

public class FileUtil {
    /**
     * 导入给字段赋值
     *
     * @param field
     * @param row
     * @param entity
     * @throws IllegalAccessException
     */
    public static void writerUploadData(Field field, Row row, Object entity) throws IllegalAccessException {
        if (field.isAnnotationPresent(CsvHeader.class)) {
            CsvHeader csvHeader = field.getAnnotation(CsvHeader.class);
            Cell cell = row.getCell(csvHeader.index());
            field.setAccessible(true);
            if (cell == null) {
                field.set(entity, null);
                return;
            }// 获取单元格的字符串值,cell解析出来是Double,会出错
            String cellValue = getCellValueAsString(cell);
            try {
                switch (csvHeader.fieldType()) {
                    case "Double":
                        field.set(entity, cellValue.isEmpty() ? null : Double.valueOf(cellValue));
                        break;
                    case "Integer":
                        field.set(entity, cellValue.isEmpty() ? null : Integer.valueOf(cellValue));
                        break;
                    case "Date":
                        try {
                            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                            field.set(entity, cellValue.isEmpty() ? null : dateFormat.parse(cellValue));
                        } catch (Exception e) {
                            field.set(entity, null);
                        }
                        break;
                    case "String":
                    default:
                        field.set(entity, cellValue);
                        break;
                }
            } catch (Exception e) {
                System.err.println("Error setting field value for " + field.getName() + ": " + e.getMessage());
                field.set(entity, null);
            }
        }
    }

    private static String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return "";
        }
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue().trim();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    // 如果是日期类型,返回标准格式日期字符串
                    return new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue());
                } else {
                    // 将数值转换为字符串,去掉小数点后的0
                    double numericValue = cell.getNumericCellValue();
                    if (numericValue % 1 == 0) {
                        return String.valueOf((int) numericValue);
                    } else {
                        return String.valueOf(numericValue);
                    }
                }
            default:
                return cell.toString().trim();
        }
    }

    /**
     * 构建标题
     *
     * @param fields
     * @param sheet
     */
    public static void writerHeader(Field[] fields, Sheet sheet) {
        // 利用反射动态构建标题行
        Arrays.sort(fields, Comparator.comparingInt(f -> f.getAnnotation(CsvHeader.class).index()));
        Row headerRow = sheet.createRow(0);
        for (Field field : fields) {
            CsvHeader header = field.getAnnotation(CsvHeader.class);
            if (header != null) {
                headerRow.createCell(header.index()).setCellValue(header.header());
            }
        }
    }

    /**
     * 写入数据
     *
     * @param station
     * @param sheet
     * @param rowNum
     * @param fields
     * @return
     * @throws IllegalAccessException
     */
    public static int writerData(Object station, Sheet sheet, int rowNum, Field[] fields) throws IllegalAccessException {
        Row row = sheet.createRow(rowNum++);
        for (Field field : fields) {
            CsvHeader header = field.getAnnotation(CsvHeader.class);
            if (header != null) {
                field.setAccessible(true);
                Object value = field.get(station);
                Cell cell = row.createCell(header.index());
                if (value != null) {
                    if ("Double".equals(header.fieldType())) {
                        cell.setCellValue((Double) value);
                    } else {
                        cell.setCellValue(value.toString());
                    }
                }
            }
        }
        return rowNum;
    }

    /**
     * 构建excel
     *
     * @param response
     * @param encodedFileName
     * @param workbook
     * @return
     * @throws IOException
     */
    public static ResponseEntity<byte[]> buildExcel(HttpServletResponse response, String encodedFileName, Workbook workbook) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        workbook.write(outputStream);
        byte[] excelBytes = outputStream.toByteArray();
        workbook.close();
        outputStream.close();

        HttpHeaders headers = new HttpHeaders();
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encodedFileName);
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);

        return new ResponseEntity<>(excelBytes, headers, HttpStatus.OK);
    }
}

实体类

package satellite.models.data;

import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import satellite.annotation.CsvHeader;


@Table(value = "zd_tide")
@Accessors(chain = true)
@NoArgsConstructor
@Data(staticConstructor = "create")

public class Tide {
    @Id
    @ApiModelProperty(value = "主键")
    @CsvHeader(index = 0,header ="主键")
    private Integer id;
    @ApiModelProperty(value = "站名")
    @CsvHeader(index = 1,header ="站名")
    private String name;
    @ApiModelProperty(value = "纬度")
    @CsvHeader(index = 2,header ="纬度",fieldType = "Double")
    private Double latitude;
    @ApiModelProperty(value = "经度")
    @CsvHeader(index = 3,header ="经度",fieldType = "Double")
    private Double longitude;
}

业务代码

package satellite.web.api;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
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.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import satellite.annotation.CsvHeader;
import satellite.models.data.Tide;
import satellite.util.FileUtil;
import satellite.web.api.base.BaseDataApi;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;


@RestController
@RequestMapping("/api/v1/tide")
@CrossOrigin(origins = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE, RequestMethod.OPTIONS})
public class TideApi extends BaseDataApi<Tide> {
    

    /**
     * 下载excel模板
     *
     * @param response
     * @throws IOException
     */
    @GetMapping("/template")
    public void downloadExcelTemplate(HttpServletResponse response) throws IOException {
        String encodedFileName = URLEncoder.encode("模板.xlsx", StandardCharsets.UTF_8.toString());
        response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("模板");
        Field[] fields = Tide.class.getDeclaredFields();
        FileUtil.writerHeader(fields, sheet);

        workbook.write(response.getOutputStream());
        workbook.close();
    }

    /**
     * 导出
     *
     * @return
     * @throws IOException
     */
    @GetMapping("/export")
    public String exportToExcel(HttpServletResponse response) throws IOException, IllegalAccessException {
        // 从数据库获取数据
//        try {
            List<Tide> stations = service.list();
            String encodedFileName = URLEncoder.encode("导出.xlsx", StandardCharsets.UTF_8.toString());
            response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName);
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            Workbook workbook = new XSSFWorkbook();
            Field[] fields = Tide.class.getDeclaredFields();
            Sheet sheet = workbook.createSheet("导出");
            // 利用反射动态构建标题行
            FileUtil.writerHeader(fields, sheet);
            // 填充数据行
            int rowNum = 1;
            for (Tide station : stations) {
                rowNum = FileUtil.writerData(station, sheet, rowNum, fields);
            }
            workbook.write(response.getOutputStream());
            workbook.close();
            return"文件导出成功";
    }

    /**
     * 导入
     *
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("/upload")
    public String uploadCSVFile(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return "上传的文件为空";
        }
        try {
            Set<Integer> existingStations = new HashSet<>();
            for (Tide tide : service.list()) {
                existingStations.add(tide.getId());
            }
            List<Tide> createList = new ArrayList<>();
            List<Tide> updateList = new ArrayList<>();
            Field[] fields = Tide.class.getDeclaredFields();

            Workbook workbook = new XSSFWorkbook(file.getInputStream());
            Sheet sheet = workbook.getSheetAt(0);
            Iterator<Row> iterator = sheet.rowIterator();
            iterator.next();  // 跳过标题行

            while (iterator.hasNext()) {
                Row row = iterator.next();
                Tide entity = new Tide();

                for (Field field : fields) {
                    if (field.isAnnotationPresent(CsvHeader.class)) {
                        FileUtil.writerUploadData(field, row, entity);
                    }
                }
                if (existingStations.contains(entity.getId())) {
                    updateList.add(entity);
                } else {
                    createList.add(entity);
                }
            }
            workbook.close();
            service.saveBatch(createList);
            service.updateBatch(updateList);
            return "文件上传成功并导入完成";
        } catch (Exception e) {
            return "处理文件时出错:请检查文件或向技术人员提供帮助: " + e.getMessage();
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值