springboot+poi 导入导出 反射

代码 :https://github.com/goodboyQAQ/poi

一.pom文件

    
        org.apache.poi
        poi
        3.15
    
    
        org.apache.poi
        poi-ooxml-schemas
        3.15
    
    
        org.apache.poi
        poi-ooxml
        3.15
    
    
        org.projectlombok
        lombok
        true
    

二.创建实体类

Result类保存一些数据信息返回给前端

@Data //生成 getting 和 setting ,equals、canEqual、hashCode、toString 方法
public class Result {
    private String msg;
    private boolean success;
    private T data;

    public Result(){
        this.success=false;
        this.msg="系统错误";
    }
}

Company是我们导入导出的数据实体类

import lombok.Data;
import lombok.EqualsAndHashCode;
import org.wang.poi.annotation.ExcelTitle;

@Data  //生成 getting 和 setting ,equals、canEqual、hashCode、toString 方法
//重写hashcode,equals判断时(id,name,tel相同就true)
@EqualsAndHashCode(callSuper = false, exclude = {"updateTime"})
//导入导出需要用到的字段
@ExcelTitle(value={"id","name","tel"},title={"编号(不能修改)","名称","电话"})
public class Company {
    private String id;
    private String name;
    private String tel;
    private String updateTime;

}

上面使用了一个自定义的注解

//指明修饰的注解,可以被例如javadoc此类的工具文档化
@Documented
 // 注解会在class字节码文件中存在,在运行时可以通过反射获取到 
@Retention(RetentionPolicy.RUNTIME)  
// 可作用在接口、类、枚举、注解
@Target(ElementType.TYPE)   
public @interface ExcelTitle {
    //字段顺序
    String[] value();
    //中文表头顺序
    String[] title();
}

三.controller类
为了方便理解,从顶层开始

@RestController
@Slf4j
public class CompanyController {

    @Autowired
    private FileUtil fileUtil;

    @Autowired
    private PoiUtil poiUtil;

    @Autowired
    private CompanyService companyService;


    //下载导入模板
    @RequestMapping(value="temp",method=RequestMethod.GET)
    public void temp(HttpServletResponse response){
        String fileName="company.xlsx"; //传入下载工具类生成下载文件名
        try{
            //user.xlsx模板文件放在resource/template下
            InputStream is=this.getClass().getResourceAsStream("/templates/company.xlsx");
            //获取输入流后实现下载
            fileUtil.download(is,fileName,response);
        }catch(Exception e){
            log.error(e.getMessage(),e);
        }
    }

    @RequestMapping(value="upload",method=RequestMethod.POST)
    public Result uplaod(@RequestParam("file")MultipartFile file){
        //MultipartFile spring支持的处理表单的file很方便
        Result result=new Result();
        try{
            //通过文件获得工作簿
            Workbook wb=poiUtil.getWorkBook(file);
            //将数据解析为我们的实体类集合
            List list=poiUtil.importExcel(wb,Company.class); //解析导入的数据
            companyService.importCompany(list);  //存入数据库
            result.setMsg("导入成功");
            result.setSuccess(true);
        }catch(Exception e){
            log.error(e.getMessage(),e);
        }
        return result;
    }

    @RequestMapping(value="download",method=RequestMethod.GET)
    public Result download(Company company,HttpServletResponse response){
        Result result=new Result();
        try{
            //查询数据
            List list=companyService.exportData(company);
            if(list.size()==0){
                result.setMsg("数据为空");
                return result;
            }
            String fileName="company.xlsx";
            InputStream is=this.getClass().getResourceAsStream("/templates/company.xlsx");
            poiUtil.exportData(fileName,list,response,Company.class);
            result.setSuccess(true);
            result.setMsg("导出成功");
        }catch(Exception e){
            log.error(e.getMessage(),e);
        }
        return result;

    }
}

四.service层
dao数据库查询,就不写了

@Service
public class CompanyServiceImpl  implements CompanyService {
    @Autowired
    private CompanyDao companyDao;

    @Override
    public void importCompany(List list) {
        if(list.size()==0){
            return;
        }
        List insertList=new ArrayList<>();
        List updateList=new ArrayList<>();
        for(Company company:list){
    	    //空值判断
            if(StringUtils.isNotEmpty(company.getId())){
                //通过id去数据库查找是否存在该条数据
                Company c=companyDao.getCompanyById(company.getId());
                //使用lombok的@EqualsAndHashCode重写了hashcode
                if(c!=null && !company.equals(c)){ //id查找的数据存在,且有更改
                    updateList.add(company);
                }
            }else{
                insertList.add(company);
            }
        }
        if(insertList.size()!=0) {
            companyDao.addCompanyList(insertList);
        }
        for(Company company:updateList){
            companyDao.updateCompany(company);
        }

    }

    @Override
    public List exportData(Company company) {
        return companyDao.exportData(company);
    }
}

五.FileUtil工具类

@Slf4j
@Component
public class FileUtil {

    /**
     *  下载文件
     * @param is  输入流
     * @param fileName  文件名
     * @param response
     */
    public void download(InputStream is, String fileName, HttpServletResponse response){
            response.setContentType("multipart/form-data");
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            byte[] buffer=new byte[1024];
            BufferedInputStream bis=null;
            OutputStream os=null;
            try{
                bis=new BufferedInputStream(is);
                os=response.getOutputStream();
                int i;
                while((i=bis.read(buffer))!=-1){
                    os.write(buffer,0,i);
                }
            }catch(Exception e){
                log.error(e.getMessage(),e);
            }finally {
                try{
                    if(bis!=null){
                        bis.close();
                    }
                }catch (Exception e){
                    log.error("缓冲输入流关闭异常");
                }
                try{
                    if(os!=null){
                        os.close();
                    }
                }catch (Exception e){
                    log.error("输出流流关闭异常");
                }
            }
    }

    public void upload(MultipartFile file){
        if(file.isEmpty()){
            return;
        }
        String fileNmae=file.getOriginalFilename();
        String filePath=System.getProperty("user.dir")+"/temp";
        File dir=new File(filePath);
        if(!dir.exists()){
            dir.mkdir();
        }
        try{
            file.transferTo(dir);
        }catch (Exception e){
            log.error(e.getMessage(),e);
        }

    }

}

六.POI工具类

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j   //可以直接使用日志方法  log.error(...);
public class PoiUtil {
    //根据文件后缀生成响应的工作簿,我这里只支持xlsx格式
    public  Workbook getWorkBook(MultipartFile file) throws Exception{
        String fileName = file.getOriginalFilename().toLowerCase();
        InputStream is = null;
        try {
            if (fileName.endsWith("xlsx")) {
                return new XSSFWorkbook(file.getInputStream());
            } else {
                throw new Exception("excel文件类型错误");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new Exception("文件格式错误");
        } finally {
            try {
                if (is != null) {
                    {
                        is.close();
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
    }


    /**
     *  导入
     * @param workbook  工作簿
     * @param clazz  对应实体类
     * @return
     */
    public List importExcel(Workbook workbook, Class clazz){
        //利用反射获取我在注解里定义好的字段顺序
        String[] fields=clazz.getAnnotation(ExcelTitle.class).value();
        List list=new ArrayList<>();  //返回的对象列表
        //获取第一个工作簿,只支持解析第一个工作簿
        Sheet sheet=workbook.getSheetAt(0);
        for(Row row:sheet){
            //第一次循环  表头跳过 
            if(row==sheet.getRow(0)){
                continue;
            }
            //第二次往后
            try {
                T t=clazz.newInstance();
                //row.getLastCellNum()获取的不是行数,是下标,所以+1
                for(int i=0;i list, HttpServletResponse response,Class clazz){
        Field[] field=clazz.getDeclaredFields();
        Workbook workbook=new XSSFWorkbook();
        Sheet sheet=workbook.createSheet();
        Row row=null;
        try {
            //获取注解中定义好的中文表头顺序
            String[] title=clazz.getAnnotation(ExcelTitle.class).title();
            //获取注解中定义好的字段顺序
            String[] fields=clazz.getAnnotation(ExcelTitle.class).value();
            for(int i=0;i<=list.size();i++){
                row=sheet.createRow(i);
                Cell cell=null;
                if(i==0){ //第一次创建标题行
                    for(int j=0;j

七.结束
前后端分离,ajax请求不能下载文件 原因

我主要是通过自定义注解定义好excel需要的字段的顺序,poiUtil传入相应的实体Class,再通过反射获取,自定义注解当然也可以用返回字段顺序的方法替代,我只是学着用用自定义注解,有更灵活的方法还望指教,谢谢。

你可能感兴趣的:(springboot+poi 导入导出 反射)