美文网首页
2019-07-31 Excel 快速导入导出 easyExce

2019-07-31 Excel 快速导入导出 easyExce

作者: 东_11f3 | 来源:发表于2019-07-31 19:10 被阅读0次

    参考链接

    解决问题

    -具官方说可以解决大文件内存泄漏问题,效率高

    源码
    (https://blog.csdn.net/alinyua/article/details/82859577
    )
    (https://github.com/wangxiaoxiongjuly/easy-excel-utils
    )

    导出

     <!--excel-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>easyexcel</artifactId>
                <version>1.1.1</version>
            </dependency>
    
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class XXXModel extends BaseRowModel {
    
        /**
         * 主键
         */
        @ExcelProperty(index = 0, value = "ID")
        private Long id;
    
        /**
         * 手机号
         */
        @ExcelProperty(index = 1, value = "手机号")
        private String phone;
    
        /**
         * 批次号
         */
        @ExcelProperty(index = 2, value = "批次号")
        private String batchNumber;
    
        /**
         * 触达状态  
         */
        @ExcelProperty(index = 3, value = "触达状态")
        private String deliveryStatusVal;
    
        /**
         * 点击状态 0 已点击 1 未点击
         */
        @ExcelProperty(index = 4, value = "点击状态")
        private String clickStatusVal;
    
        /**
         * 长链点击次数 pv
         */
        @ExcelProperty(index = 5, value = "pv")
        private Integer linkClickCount;
    
        /**
         * 按钮点击次数
         */
        @ExcelProperty(index = 6, value = "按钮点击")
        private Integer buttonClickCount;
    
        /**
         * 发送时间
         */
        @ExcelProperty(index = 7, value = "发送时间")
        private String smsSendTime;
    
    
    
        public static XXXModel fromSmsEventVo(xxx smsEventVo){
    
            return XXXModel.builder()
                    .id(smsEventVo.getId())
                    .phone(smsEventVo.getPhone())
                    .batchNumber(smsEventVo.getBatchNumber())
                    .deliveryStatusVal(smsEventVo.getDeliveryStatusVal())
                    .clickStatusVal(smsEventVo.getClickStatusVal())
                    .linkClickCount(smsEventVo.getLinkClickCount())
                    .buttonClickCount(smsEventVo.getButtonClickCount())
                    .smsSendTime(TimeUtil.DateToString(smsEventVo.getSmsSendTime(),"yyyy-MM-dd HH:mm:ss"))
                    .build();
    
        }
    }
    
        @ApiOperation(value = "xxxexcel导出")
        @RequestMapping(value = "/export", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
        @ApiImplicitParams({
                @ApiImplicitParam(paramType = "header",name = "x-auth-token", value = "token授权验证", required = true, dataType = "String")
    
        })
        public void smsEventListExport(@RequestHeader("x-auth-token") String token,
                                                 @RequestBody XXXVo xxxVo,
                                                 HttpServletRequest request, HttpServletResponse response) throws IOException {
    
    
            log.info("findSmsBatchEventList.requestParam=[{}]", JSONObject.toJSONString(smsEventQueryVo));
    
            ServletOutputStream out = response.getOutputStream();
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setCharacterEncoding("utf-8");
            String fileName = new String(("excel " + new SimpleDateFormat("yyyy-MM-dd").format(new Date()))
                    .getBytes(), "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(fileName + ".xlsx", "utf-8"));
    
            List<sss> list = smsService.findSmsEventListExport(xxx);
            List<ExcelSmsEventModel> excelSmsEventModels = list.stream().filter(m -> m != null)
                    .map(XXXModel::fromSmsEventVo).collect(Collectors.toList());
    
            ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);
            Sheet sheet1 = new Sheet(1, 0, XXXModel.class);
            sheet1.setSheetName("sheet1");
            writer.write(excelSmsEventModels, sheet1);
            writer.finish();
            out.flush();
    
        }
    

    导入

    导入问题

    • 会出现xlsx/xls 导入失败;inputStream = new BufferedInputStream(excel.getInputStream());
      改成buffer流,否则报错
     /**
         * 手机号导入
         * @param request
         * @return
         */
        @ApiOperation(value = "手机号导入")
        @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
        @ApiImplicitParams({
                @ApiImplicitParam(paramType = "header",name = "x-auth-token", value = "token授权验证", required = true, dataType = "String")
    
        })
        @ResponseBody
        public ResponseResult importExcel(@ApiParam(value = "上传的文件", required = true)
                                      @RequestParam(value = "file")MultipartFile request,
                                          @RequestHeader("x-auth-token") String token){
    
           return smsBatchService.phoneImport(request);
        }
    
     @Override
        @Transactional
        public ResponseResult phoneImport(MultipartFile request) {
            String filename = request.getOriginalFilename();
            if (StringUtils.isEmpty(request)) {
                return ResponseResult.build(HttpServletResponse.SC_OK, "文件不存在", null, true);
            }
            // 上传excel 保存服务器路径
            String excelFullPath = "";
            try {
                List<ImportPhoneModel> list = ExcelUtil.readExcel(request,ImportPhoneModel.class);
               
            } catch (ExcelException e) {
                e.printStackTrace();
                log.info("phoneImport.fail");
                return ResponseResult.build(HttpServletResponse.SC_NOT_ACCEPTABLE, e.getMessage(), null, true);
            }
    
            //excel上传服务器 必须放在后面
            try {
                log.info("phoneImport.transferTo:begin");
                request.transferTo(new File(excelFullPath));
                log.info("phoneImport.transferTo:success");
    
            } catch (IOException e) {
                e.printStackTrace();
                return ResponseResult.build(HttpServletResponse.SC_NOT_ACCEPTABLE, "上传失败", null, true);
    
            }
            return ResponseResult.build(HttpServletResponse.SC_OK, "上传成功",  null, true);
        }
    
    public class ExcelException extends Exception {
        /**
         * Constructs a new exception with the specified detail message.  The
         * cause is not initialized, and may subsequently be initialized by
         * a call to {@link #initCause}.
         *
         * @param message the detail message. The detail message is saved for
         *                later retrieval by the {@link #getMessage()} method.
         */
        public ExcelException(String message) {
            super(message);
        }
    }
    
    
    import org.apache.poi.ss.usermodel.IndexedColors;
    
    import java.lang.annotation.*;
    
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface CellFontFormat {
    
        String fontName() default "";
    
        short fontHeightInPoints() default 11;
    
        IndexedColors fontColor() default IndexedColors.BLACK;
    
        boolean bold() default false;
    }
    
    
    import org.apache.poi.ss.usermodel.HorizontalAlignment;
    import org.apache.poi.ss.usermodel.IndexedColors;
    
    import java.lang.annotation.*;
    
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface CellStyleFormat {
    
        /**
         * 水平居中方式 默认左居中
         * @see HorizontalAlignment
         */
        HorizontalAlignment horizontalAlignment() default HorizontalAlignment.LEFT;
    
        /**
         * 字体设置
         * @see org.apache.poi.xssf.usermodel.XSSFFont
         * @see org.apache.poi.hssf.usermodel.HSSFFont
         */
        CellFontFormat cellFont() default @CellFontFormat();
    
    
        /**
         * 背景颜色
         * @see IndexedColors
         */
        IndexedColors fillBackgroundColor() default IndexedColors.WHITE;
    
    }
    
    import com.alibaba.excel.annotation.ExcelProperty;
    import com.alibaba.excel.context.AnalysisContext;
    import com.alibaba.excel.event.AnalysisEventListener;
    
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.List;
    
    public class ExcelListener extends AnalysisEventListener {
    
        private List<Object> dataList = new ArrayList<>();
    
        /**
         * 通过 AnalysisContext 对象还可以获取当前 sheet,当前行等数据
         */
        @Override
        public void invoke(Object object, AnalysisContext context) {
            if(!checkObjAllFieldsIsNull(object)) {
                dataList.add(object);
            }
        }
    
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            //do something
        }
    
        private static final String SERIAL_VERSION_UID = "serialVersionUID";
    
        /**
         * 判断对象中属性值是否全为空
         */
        private static boolean checkObjAllFieldsIsNull(Object object) {
            if (null == object) {
                return true;
            }
            try {
                for (Field f : object.getClass().getDeclaredFields()) {
                    f.setAccessible(true);
                    //只校验带ExcelProperty注解的属性
                    ExcelProperty property = f.getAnnotation(ExcelProperty.class);
                    if(property == null || SERIAL_VERSION_UID.equals(f.getName())){
                        continue;
                    }
                    if (f.get(object) != null && MyStringUtils.isNotBlank(f.get(object).toString())) {
                        return false;
                    }
                }
            } catch (Exception e) {
                //do something
            }
            return true;
        }
    
        public List<Object> getDataList() {
            return dataList;
        }
    }
    
    
    import com.alibaba.excel.ExcelReader;
    import com.alibaba.excel.metadata.BaseRowModel;
    import com.alibaba.excel.metadata.Sheet;
    import com.alibaba.excel.support.ExcelTypeEnum;
    import com.geotmt.etc.controller.excel.utils.exception.ExcelException;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.servlet.http.HttpServletResponse;
    import java.io.BufferedInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * ExcelUtil
     * 基于easyExcel的开源框架,poi版本3.17
     * BeanCopy ExcelException 属于自定义数据,属于可自定义依赖
     * 工具类尽可能还是需要减少对其他java的包的依赖
     * Created by fdd on 2019/7/26.
     */
    public class ExcelUtil {
        /**
         * 私有化构造方法
         */
        private ExcelUtil(){}
    
        /**
         * 读取 Excel(多个 sheet)
         * 将多sheet合并成一个list数据集,通过自定义ExcelReader继承AnalysisEventListener
         * 重写invoke doAfterAllAnalysed方法
         * getExtendsBeanList 主要是做Bean的属性拷贝 ,可以通过ExcelReader中添加的数据集直接获取
         * @param excel    文件
         * @param rowModel 实体类映射,继承 BaseRowModel 类
         * @return Excel 数据 list
         */
        public static <T extends BaseRowModel> List<T> readExcel(MultipartFile excel,Class<T>  rowModel) throws ExcelException {
            ExcelListener excelListener = new ExcelListener();
            ExcelReader reader = getReader(excel, excelListener);
            if (reader == null) {
                return new ArrayList<>();
            }
            for (Sheet sheet : reader.getSheets()) {
                sheet.setClazz(rowModel);
                reader.read(sheet);
            }
            return getExtendsBeanList(excelListener.getDataList(),rowModel);
        }
    
        /**
         * 读取某个 sheet 的 Excel
         * @param excel    文件
         * @param rowModel 实体类映射,继承 BaseRowModel 类
         * @param sheetNo  sheet 的序号 从1开始
         * @return Excel 数据 list
         */
        public static <T extends BaseRowModel> List<T> readExcel(MultipartFile excel, Class<T>  rowModel, int sheetNo)  throws ExcelException{
            return readExcel(excel, rowModel, sheetNo, 1);
        }
    
        /**
         * 读取某个 sheet 的 Excel
         * @param excel       文件
         * @param rowModel    实体类映射,继承 BaseRowModel 类
         * @param sheetNo     sheet 的序号 从1开始
         * @param headLineNum 表头行数,默认为1
         * @return Excel 数据 list
         */
        public static <T extends BaseRowModel> List<T> readExcel(MultipartFile excel, Class<T>  rowModel, int sheetNo,
                                                                 int headLineNum) throws ExcelException {
            ExcelListener excelListener = new ExcelListener();
            ExcelReader reader = getReader(excel, excelListener);
            if (reader == null) {
                return new ArrayList<>();
            }
            reader.read(new Sheet(sheetNo, headLineNum, rowModel));
            return getExtendsBeanList(excelListener.getDataList(),rowModel);
        }
    
    
        /**
         * 导出 Excel :多个 sheet,带表头
         * @param response  HttpServletResponse
         * @param list      数据 list,每个元素为一个 BaseRowModel
         * @param fileName  导出的文件名
         * @param sheetName 导入文件的 sheet 名
         * @param object    映射实体类,Excel 模型
         */
        public static ExcelWriterFactory writeExcelWithSheets(HttpServletResponse response, List<? extends BaseRowModel> list,
                                                              String fileName, String sheetName, BaseRowModel object, ExcelTypeEnum excelTypeEnum) throws ExcelException {
            ExcelWriterFactory writer = new ExcelWriterFactory(getOutputStream(fileName, response,excelTypeEnum), excelTypeEnum);
            Sheet sheet = new Sheet(1, 0, object.getClass());
            sheet.setSheetName(sheetName);
            writer.write(list, sheet);
            return writer;
        }
    
        /**
         * 导出文件时为Writer生成OutputStream
         */
        private static OutputStream getOutputStream(String fileName, HttpServletResponse response, ExcelTypeEnum excelTypeEnum) throws ExcelException{
            //创建本地文件
            String filePath = fileName + excelTypeEnum.getValue();
            try {
                fileName = new String(filePath.getBytes(), "ISO-8859-1");
                response.addHeader("Content-Disposition", "filename=" + fileName);
                return response.getOutputStream();
            } catch (IOException e) {
                throw new ExcelException("创建文件失败!");
            }
        }
    
        /**
         * 返回 ExcelReader
         * @param excel         需要解析的 Excel 文件
         * @param excelListener new ExcelListener()
         */
        private static ExcelReader getReader(MultipartFile excel,
                                             ExcelListener excelListener) throws ExcelException{
            String fileName = excel.getOriginalFilename();
            if (fileName == null ) {
                throw new ExcelException("文件格式错误!");
            }
            if (!fileName.toLowerCase().endsWith(ExcelTypeEnum.XLS.getValue()) && !fileName.toLowerCase().endsWith(ExcelTypeEnum.XLSX.getValue())) {
                throw new ExcelException("文件格式错误!");
            }
            InputStream inputStream;
    
            try {
                inputStream = new BufferedInputStream(excel.getInputStream());
    //            , ExcelTypeEnum.XLSX
                return new ExcelReader(inputStream,null, excelListener, false);
            } catch (IOException e) {
                //do something
            }
            return null;
        }
    
        /**
         * 利用BeanCopy转换list
         */
        public static <T extends BaseRowModel> List<T> getExtendsBeanList(List<?> list,Class<T> typeClazz){
            return MyBeanCopy.convert(list,typeClazz);
        }
    }
    
    import com.alibaba.excel.ExcelWriter;
    import com.alibaba.excel.metadata.BaseRowModel;
    import com.alibaba.excel.metadata.Sheet;
    import com.alibaba.excel.support.ExcelTypeEnum;
    
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.List;
    
    public class ExcelWriterFactory extends ExcelWriter {
        private OutputStream outputStream;
        private int sheetNo = 1;
    
        ExcelWriterFactory(OutputStream outputStream, ExcelTypeEnum typeEnum) {
            super(outputStream, typeEnum);
            this.outputStream = outputStream;
        }
    
        public ExcelWriterFactory write(List<? extends BaseRowModel> list, String sheetName,
                                        BaseRowModel object) {
            this.sheetNo++;
            try {
                Sheet sheet = new Sheet(sheetNo, 0, object.getClass());
                sheet.setSheetName(sheetName);
                this.write(list, sheet);
            } catch (Exception ex) {
                try {
                    outputStream.flush();
                } catch (IOException e) {
                    //do something
                }
            }
            return this;
        }
    
        @Override
        public void finish() {
            super.finish();
            try {
                outputStream.flush();
            } catch (IOException e) {
                //do something
            }
        }
    
        public void close(){
            try {
                outputStream.close();
            } catch (IOException e) {
                //do something
            }
        }
    }
    
    import org.springframework.beans.*;
    import org.springframework.beans.propertyeditors.CustomDateEditor;
    import org.springframework.core.convert.ConversionService;
    import org.springframework.core.convert.converter.Converter;
    import org.springframework.core.convert.support.DefaultConversionService;
    import org.springframework.core.convert.support.GenericConversionService;
    import org.springframework.util.Assert;
    
    import java.beans.PropertyDescriptor;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Date;
    import java.util.List;
    
    public class MyBeanCopy {
    
        private final class DateToStringConverter implements Converter<Date, String> {
            private DateFormat df ;
            private DateToStringConverter(String format) {
                df = new SimpleDateFormat(format);
            }
            @Override
            public String convert(Date source) {
    
                return df.format(source);
            }
        }
    
        private static final String DATE_FORMAT = "yyyy-MM-dd";
    
        private static Object convertForProperty(Wrapper wrapper, Object object, Object value, String propertyName)
                throws TypeMismatchException {
            Object result;
            if (wrapper == null) {
                result = null;
            } else {
                wrapper.setWrappedInstance(object);
                result = wrapper.getBeanWrapper().convertForProperty(value, propertyName);
            }
            return result;
        }
    
        private static Object copyProperties(Object source, Object target) throws BeansException {
            Wrapper wrapper = new MyBeanCopy().new Wrapper(source);
            copyProperties(wrapper, source, target);
            return target;
        }
    
        /**
         * Copy the property values of the given source bean into the target bean.
         * <p>
         * Note: The source and target classes do not have to match or even be derived from each other, as long as the properties match. Any bean
         * properties that the source bean exposes but the target bean does not will silently be ignored.
         * <p>
         * This is just a convenience method. For more complex transfer needs, consider using a full BeanWrapper.
         * 
         * @param source
         *            the source bean
         * @param target
         *            the target bean
         * @throws BeansException
         *             if the copying failed
         */
        private static void copyProperties(Wrapper wrapper, Object source, Object target) throws BeansException {
            Assert.notNull(source, "Source must not be null");
            Assert.notNull(target, "Target must not be null");
    
            Class<?> actualEditable = target.getClass();
            PropertyDescriptor[] targetPds = BeanUtils.getPropertyDescriptors(actualEditable);
    
            for (PropertyDescriptor targetPd : targetPds) {
                if (targetPd.getWriteMethod() != null) {
                    PropertyDescriptor sourcePd = BeanUtils.getPropertyDescriptor(source.getClass(), targetPd.getName());
                    if ( sourcePd.getReadMethod() != null) {
                        try {
                            Method readMethod = sourcePd.getReadMethod();
                            if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                                readMethod.setAccessible(true);
                            }
                            Object value = readMethod.invoke(source);
                            // 判断是否类型不一致
                            if (value != null && !(targetPd.getPropertyType().isInstance(value))) {
                                // 数据转型
                                value = convertForProperty(wrapper, target, value, targetPd.getName());
                            }
                            Method writeMethod = targetPd.getWriteMethod();
                            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                writeMethod.setAccessible(true);
                            }
                            writeMethod.invoke(target, value);
                        } catch (Exception ex) {
                            throw new FatalBeanException("Could not copy properties from source to target", ex);
                        }
                    }
                }
            }
    
        }
    
        private final class Wrapper {
    
            private GenericConversionService conversion;
            private BeanWrapperImpl bean;
    
            private Wrapper(Object object) {
                conversion = initDefaultConversionService();
                bean = initDefaultBeanWrapper(conversion, object);
            }
    
            private void setWrappedInstance(Object object) {
                bean.setWrappedInstance(object);
            }
    
            private GenericConversionService initDefaultConversionService() {
                GenericConversionService conversionService = new DefaultConversionService();
                conversionService.addConverter(new DateToStringConverter(DATE_FORMAT));
                return conversionService;
            }
    
            private BeanWrapperImpl initDefaultBeanWrapper(@SuppressWarnings("hiding") ConversionService conversion,
                                                           Object object) {
                BeanWrapperImpl beanWrapper = new BeanWrapperImpl(object);
                beanWrapper.setConversionService(conversion);
                SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
                dateFormat.setLenient(false);
                beanWrapper.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
                return beanWrapper;
            }
    
            private BeanWrapperImpl getBeanWrapper() {
                return bean;
            }
        }
    
        /**
         * 复制源对象到目的对象
         */
        private static void convert(Object source, Object target) {
            copyProperties(source, target);
        }
    
        public static <T> List<T> convert(List<?> sources, Class<T> targetClass) {
            List<?> sourcesObj = sources;
            if (sourcesObj == null) {
                sourcesObj = Collections.emptyList();
            }
            List<T> targets = new ArrayList<>(sourcesObj.size());
            MyBeanCopy.convert(sourcesObj, targets, targetClass);
            return targets;
        }
    
        private static <T> void convert(List<?> sources, List<T> targets, Class<T> targetClass) {
            if (targets == null) {
                return;
            }
            targets.clear();
            if (sources == null) {
                return;
            }
            for (Object obj : sources) {
                try {
                    T target = targetClass.newInstance();
                    targets.add(target);
                    convert(obj, target);
                } catch (Exception e) {
                    //do something
                    return;
                }
            }
        }
    }
    public class MyStringUtils {
    
        private MyStringUtils() {}
    
        private static boolean isBlank(final CharSequence cs) {
            int strLen;
            if (cs == null || (strLen = cs.length()) == 0) {
                return true;
            }
            for (int i = 0; i < strLen; i++) {
                if (!Character.isWhitespace(cs.charAt(i))) {
                    return false;
                }
            }
            return true;
        }
    
        public static boolean isNotBlank(final CharSequence cs) {
            return !isBlank(cs);
        }
    }
    
    
    

    相关文章

      网友评论

          本文标题:2019-07-31 Excel 快速导入导出 easyExce

          本文链接:https://www.haomeiwen.com/subject/chfxdctx.html