java导出excel包含图片

最近有需要导出用户留言的数据,包含用户留言的上传的照片

在网上找了很多,整合一些,最后实现了业务,导出来有点丑,后续再做优化,代码功能有局限性,看到的小伙伴如果有好的想法可以说说,让我学习学习
最后实现的效果(似乎一个格子不能放多张图片?)

直接上代码:

导入maven依赖
<!-- poi读取excle -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>3.9</version>
    </dependency>
1
2
3
4
5
6
Controller类

    /**
     * 下载用户留言信息
     * @date 2021/01/11
     * @param query
     * @param request
     * @param response
     */
    @ApiOperation(value = "下载用户留言信息",
            notes = "")
    @RequestMapping(value="exeportData",method={RequestMethod.POST,RequestMethod.GET})
    public void exeportData(@RequestBody(required=false) UserMessageQuery query, HttpServletRequest request, HttpServletResponse response) throws Exception {
        if(query==null){
            query = new UserMessageQuery();
        }
        query.setVenderId(PublicUtil.getCustomerId()); //这是我的查询条件
        //查询任务
        List<UserMessage> data = userMessageService.selectList(query);

        Map<String, Object> objMap = new HashMap<>();
        List<Map<String,Object>> list = new ArrayList<>();
        String path= "/data/nginxd/sportsApplets/excelDeleteImage/";
        if(data.size()>0){
            for (UserMessage userMessage: data) {
                //通过留言id去获取留言上传的图片列表
                List<String> imgList = userMessageImgService.selectImg(userMessage.getId());
                UserMessageExcel excelObj = new UserMessageExcel();
                excelObj.setNickName(userMessage.getNickName());
                excelObj.setCreateTime(PublicUtil.getDateString(userMessage.getCreateTime()));
                excelObj.setContent(userMessage.getContent());

                File[] files = new File[imgList.size()];
                if(imgList.size()>0){
                    for (int i =0 ; i< imgList.size(); i++){
                        String filePath = ImageExcelUtil.saveFile(imgList.get(i), path);  //由于我的是远程服务器的网络图片,所以我先保存到本地,如果是本地服务器图片,不需要保存这一步
                        files[i] = new File(filePath);
                    }
                }
                excelObj.setImages(files);
                objMap = ImageExcelUtil.javaBean2Map(excelObj);
                list.add(objMap);
            }
        }
        Object[] objects = objMap.keySet().toArray();
        String[] titles = new String[objects.length];
        Map<String, String> map = getMap();
        for(int i=0;i<titles.length;i++){
            String key = objects[i].toString();
            titles[i] = map.get(key);
        }

        String fileName = "用户留言信息记录"+PublicUtil.getShortDateString(new Date());
        response.setContentType("application/vnd.ms-excel");
        response.addHeader("Content-Disposition", "attachment; filename="+fileName);
        ImageExcelUtil.excelOut(titles,list.size(),list,fileName, response, path);
    }

    /**
     * 每一列数据的标题
     * @date 2021/01/11
     * @return Map<String,String>
     */
    public Map<String, String> getMap(){
        Map<String, String> map = new HashMap<>();
        map.put("nickName","用户昵称");
        map.put("createTime","留言时间");
        map.put("content","留言内容");
        map.put("images","图片");
        return map;
    }
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
导出工具类:

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class ImageExcelUtil {
    
    private static final Log log = LogFactory.getLog(ImageExcelUtil.class);

    /**
     * excel工具类,可导出带图片或不带图片的数据
     * @date 2021/01/11
     * @param titles 第一行的标题列
     * @param rows 数据行量
     * @param maps 装载导出数据的封装了map的list数据集合,注意:此中的map尽量用本类中的方法 javaBean2Map直接生成,或自己拼接;但需与参数titles[]的标题相关数据对应上
     * @param fileName 导出到本地的文件路径和文件名
     * @param response response
     * @param path 保存到本地的图片地址(我这里是为了删除该目录下的图片,因为我是把网络图片保存到到本地的,如果图片已经是本地图片的话就不需要删除)
     */
    public static void excelOut(String[] titles, int rows, List<Map<String,Object>> maps, String fileName,
                               HttpServletResponse response, String path){

        OutputStream out = null;
        BufferedImage bufferImg = null;
        HSSFWorkbook wb = null;

        try{
            //创建工作sheet
            wb = new HSSFWorkbook();
            HSSFSheet sheet = wb.createSheet(fileName);
            //设置单元格内容水平垂直居中
            HSSFCellStyle style = wb.createCellStyle();
            style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
            style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
            style.setWrapText(true); //设置内容自动换行

            //画图的顶级管理器,一个sheet只能获取一个(一定要注意这点)
            HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
            HSSFRow row0 = sheet.createRow(0);
            row0.setHeightInPoints(25);
            if (titles.length == 0){
                return ;
            }
            HSSFCell cell = null;
            //第一行、标题行列
            for (int i=0;i<titles.length;i++){
                cell = row0.createCell(i);     //第一个单元格
                cell.setCellValue(titles[i]);         //设定值
                cell.setCellStyle(style);
                sheet.setColumnWidth(i,6000);
            }

            HSSFRow row = null;
            HSSFCell cellRow = null;
            HSSFClientAnchor anchor = null;

            for (int i=1;i<=rows;i++){
                int cellColumn = 0;
                //创建行
                row = sheet.createRow(i);
                //设置默认行高
                row.setHeightInPoints(25);
                //行数据处理
                Map<String, Object> stringObjectMap = maps.get(i - 1);
                for(Object value : stringObjectMap.keySet()){
                    //行单元格
                    cellRow = row.createCell(cellColumn);
                    cellRow.setCellStyle(style);
                    //如果行数据中有图片时候的处理
                    if (value.equals("images")){
                        File[] file = (File[]) stringObjectMap.get(value);
                        if (file == null || file.length == 0){
                            cellRow.setCellValue("");
                            continue;
                        }else{
                            row.setHeightInPoints(50);

                            for (int x=0;x<file.length;x++){
                                ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
                                if (x>0){
                                    cellRow = row.createCell(cellColumn);
                                    cellRow.setCellStyle(style);
                                }
                                sheet.setColumnWidth(cellColumn,5000);
                                log.error("图片路径"+file[x]);
                                bufferImg = ImageIO.read(file[x]);
                                ImageIO.write(bufferImg, "jpg", byteArrayOut);
                                anchor = new HSSFClientAnchor(0, 0, 1023, 255,(short) cellColumn, i, (short) cellColumn, i);
                                anchor.setAnchorType(3);
                                patriarch.createPicture(anchor, wb.addPicture(byteArrayOut.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG));
                                cellColumn++;
                            }
                            continue;
                        }
                    }
                    cellRow.setCellValue(stringObjectMap.get(value).toString());
                    cellColumn ++;
                }

            }
            if(wb!=null){
                out = response.getOutputStream();
                response.setContentType("application/x-msdownload");
                response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8") +".xls");
                // 写入excel文件
                wb.write(out);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(out != null){
                try {
                    out.close();

                    //执行删除生成的图片 TODO
//                    File file = new File("E:\\data\\nginxd\\sportsApplets");//输入要删除文件目录的绝对路径
//                    File file = new File("/data/nginxd/sportsApplets/excelDeleteImage/");//输入要删除文件目录的绝对路径
                    File file = new File(path);//输入要删除文件目录的绝对路径
                    deleteFile(file);//由于是保存网络图片到本地服务区,所以画完图片到excel就要删除文件
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    /**
     * 删除文件夹目录下的所有文件 (我是怕到时候本地服务器图片越来越多,占用资源,所以把图片洗完到excel里面就删除)
     * @date 2021/01/11
     * @param file
     */
    public static void deleteFile(File file){
        //判断文件不为null或文件目录存在
        if (file == null || !file.exists()){
            log.error("文件删除失败,请检查文件路径是否正确");
            return;
        }
        //取得这个目录下的所有子文件对象
        File[] files = file.listFiles();
        //遍历该目录下的文件对象
        for (File f: files){
            //打印文件名
            String name = file.getName();
            log.error("删除的文件名"+name);
            //判断子目录是否存在子目录,如果是文件则删除
            if (f.isDirectory()){
                deleteFile(f);
            }else {
                f.delete();
            }
        }
        //删除空文件夹  for循环已经把上一层节点的目录清空。
        file.delete();
    }

    /**
     * 保存图片到本地
     * @date 2021/01/11
     * @param imageUrl
     * @param path
     * @return
     */
    public static String saveFile(String imageUrl, String path){
        String filename = imageUrl.substring(imageUrl.lastIndexOf("/")+1, imageUrl.length());
        log.error("图片===="+filename);
//        Random rand = new Random();
//        int s = rand.nextInt(900)+ 100;
        int s = (int) (Math.random() * 10000);
        log.error("随机数=="+s);
        filename = s + filename;  //这里如果有文件名称重复的,就取一个随机数拼接文件名
        File sf= null;
        OutputStream os = null;
        InputStream is = null;
        try {
            // 构造URL
            URL url = new URL(imageUrl);
            // 打开连接
            URLConnection con = url.openConnection();
            //设置请求超时为5s
            con.setConnectTimeout(5*1000);
            // 输入流
            is = con.getInputStream();

            // 1K的数据缓冲
            byte[] bs = new byte[1024];
            // 读取到的数据长度
            int len;
            // 输出的文件流
//            String path = "E:\\data\\nginxd\\sportsApplets";
//          String path = "/data/nginxd/sportsApplets/excelDeleteImage/";
            sf = new File(path);
            if(!sf.exists()){
                sf.mkdirs();
            }
            os = new FileOutputStream(sf.getPath()+"/"+filename);
            // 开始读取
            while ((len = is.read(bs)) != -1) {
                os.write(bs, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 完毕,关闭所有链接
            try {
                if(os!=null){
                    os.close();
                }
                if(is!=null){
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sf.getPath()+"/"+filename;
    }


    /**
     * 将java类对象属性-值转换成map的键值对 去除getClass方法属性,以及自定义的file属性放置最后。
     * @date 2021/01/11
     * @param javaBean
     * @return Map
     * @throws Exception
     */
    public static Map<String, Object> javaBean2Map(Object javaBean) throws Exception {
        Map<String, Object> map = new LinkedHashMap<>();
        //反射的实现方式:第一种
        /*Class<Student> studentClass = Student.class;
        studentClass.getClass();*/
        //第二种实现方式
        Method[] methods = javaBean.getClass().getMethods(); // 获取所有方法
        //第三种实现方式
        /*Class.forName("类路径");*/
        String fileName = null;
        File[] files = null;
        for (Method method : methods) {
            if (method.getName().startsWith("get")) {
                String field = method.getName(); // 拼接属性名
                if (field.contains("getClass")){
                    continue;
                }
                field = field.substring(field.indexOf("get") + 3);
                field = field.toLowerCase().charAt(0) + field.substring(1);
                Object value = method.invoke(javaBean, (Object[]) null); // 执行方法
                if (field.equals("images")){
                    fileName = field;
                    files = (File[]) value;
                    continue;
                }
                map.put(field, value);
            }
        }
        if (fileName != null){
            map.put(fileName,files);
        }
        return map;
    }

    /**
     * 递归调用让字符串对中调换
     * @date 2021/01/11
     * @param originStr
     * @return String
     */
    public static String reverse(String originStr) {
        if(originStr == null || originStr.length() <= 1)
            return originStr;
        String substring = originStr.substring(1);
        String s = reverse(substring) + originStr.charAt(0);
        return s;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
导出对象实体类:


import java.io.File;
import java.io.Serializable;
import java.util.Date;

public class UserMessageExcel implements Serializable{

    /**
     *序列化ID
     */
    private static final long serialVersionUID = 1L;
    /**
     * 用户昵称
     */
    private String nickName;
    /**
     * 创建时间(留言时间)
     */
    private String createTime;
    /**
     * 留言内容
     */
    private String content;
    /**
     * 图片数组
     */
    private File[] images;

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getCreateTime() {
        return createTime;
    }

    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public File[] getImages() {
        return images;
    }

    public void setImages(File[] images) {
        this.images = images;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
总结
本代码扩张性不强,时间比较急,后续再慢慢优化,写此记录下
————————————————
版权声明:本文为CSDN博主「qwer码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yuanyixuan23/article/details/112573197

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值