一、設計出的簡歷模板圖以及給的簡歷小圖標切圖
二、按照簡歷模板圖新建簡歷word文件 :${字段名},同時將圖片插入到word中,並將建好的word文件另存為xml文件;
三、直接將該xml文件重命名為.ftl文件,並用編輯器(EditPlus)打開並修改
說明:字段取值用Map來存取;
${pictureAddrees!"...."} pictureAddress中存的是圖片轉換后的64位碼,!(感嘆號)表示當字段值為空時取后面的默認圖片的64位碼;
集合數據循環取值形式如圖所示。
四、項目pom文件中加入freemarker的依賴,將ftl文件放到resource目錄下
<!--添加freeMarker--> <!-- https://mvnrepository.com/artifact/org.freemarker/freemarker --> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.23</version> </dependency>
五、工具類代碼如下:
1、createWord(Map dataMap, String templateName, String fileFullPath) ==> 根據傳入的數據、模板文件名、生成文件全路徑名(帶.doc)來創建word文件到磁盤;
2、createZip(String zipfullPath,String[] fileFullPaths) ==> 用流的方式根據生成的文件路徑名(帶.zip)、要打包的word文件全路徑名數組(帶.doc)來打包zip文件到磁盤;
3、createZip(String zipfullPath,String fileFullPath,boolean isKeepDirStr) ==> 用流的方式生成zip文件,調用compressZip()方法
compressZip(InputStream inputStream,ZipOutputStream zip, File sourceFile, String fileName,boolean isKeepDirStr) ==> 遞歸壓縮文件夾,被調用
注意:當生成的zip文件為帶文件夾目錄級別時,調用3方法;
當生成的zip文件為純文件時,調用2方法。
4、downLoadFile(String fullPath, HttpServletResponse response) ==> 用流的方式下載生成的word文件、zip文件或其他文件;
5、createFromUrl(String urlAddress,String fileFullPath) ==> 從網絡地址下載文件到磁盤;
如插入簡歷的圖片需要從網絡地址下載到磁盤,再生成base64位碼,否則會失敗;
個人的一些視頻信息地址、附件地址也需要從網絡地址下載到磁盤,保存后再一起和簡歷word打包成zip文件下載。
6、getImageBase(String urlAddress,String pathAddress) ==> 生成圖片的Base64位碼。
1 package com.hs.zp.common.utils; 2 3 import freemarker.template.Configuration; 4 import freemarker.template.Template; 5 import freemarker.template.TemplateExceptionHandler; 6 7 import java.io.*; 8 import java.net.URL; 9 import java.util.Map; 10 11 import javax.servlet.http.HttpServletResponse; 12 import javax.xml.soap.Text; 13 14 import org.apache.commons.codec.binary.Base64; 15 import org.apache.log4j.Logger; 16 import org.apache.tools.zip.ZipEntry; 17 import org.apache.tools.zip.ZipOutputStream; 18 19 import com.google.common.io.Files; 20 21 /** 22 * 23 * @Descript TODO (利用freemark生成word及zip) 24 * @author yeting 25 * @date 2019年3月19日 26 * 27 */ 28 public class WordUtil { 29 public static Logger logger = Logger.getLogger(WordUtil.class); 30 31 /** 32 * 生成word文件(全局可用) 33 * @param dataMap word中需要展示的動態數據,用map集合來保存 34 * @param templateName word模板名稱,例如:test.ftl 35 * @param fileFullPath 要生成的文件全路徑 36 */ 37 @SuppressWarnings("unchecked") 38 public static void createWord(Map dataMap, String templateName, String fileFullPath) { 39 logger.info("【createWord】:==>方法進入"); 40 logger.info("【fileFullPath】:==>" + fileFullPath); 41 logger.info("【templateName】:==>" + templateName); 42 43 try { 44 // 創建配置實例 45 Configuration configuration = new Configuration(); 46 logger.info("【創建配置實例】:==>"); 47 48 // 設置編碼 49 configuration.setDefaultEncoding("UTF-8"); 50 logger.info("【設置編碼】:==>"); 51 52 // 設置處理空值 53 configuration.setClassicCompatible(true); 54 55 // 設置錯誤控制器 56 // configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); 57 58 // String pathName = Text.class.getResource("/template").getFile(); 59 // File templateFile = new File(pathName); 60 // logger.info("【pathName】:==>" + pathName); 61 // logger.info("【templateFile】:==>" + templateFile.getName()); 62 // configuration.setDirectoryForTemplateLoading(templateFile); 63 64 // 設置ftl模板文件加載方式 65 configuration.setClassForTemplateLoading(WordUtil.class,"/template"); 66 67 //創建文件 68 File file = new File(fileFullPath); 69 // 如果輸出目標文件夾不存在,則創建 70 if (!file.getParentFile().exists()) { 71 file.getParentFile().mkdirs(); 72 } 73 74 // 將模板和數據模型合並生成文件 75 Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); 76 // 獲取模板 77 Template template = configuration.getTemplate(templateName); 78 // 生成文件 79 template.process(dataMap, out); 80 81 // 清空緩存 82 out.flush(); 83 // 關閉流 84 out.close(); 85 86 } catch (Exception e) { 87 logger.info("【生成word文件出錯】:==>" + e.getMessage()); 88 e.printStackTrace(); 89 } 90 } 91 92 /** 93 * 生成zip文件,根據文件路徑不帶子文件夾(全局可用) 94 * @param zipfullPath 壓縮后的zip文件全路徑 95 * @param fileFullPaths 壓縮前的文件全路徑數組 96 */ 97 public static void createZip(String zipfullPath,String[] fileFullPaths) { 98 InputStream inputStream = null; 99 ZipOutputStream zip = null; 100 101 try { 102 zip = new ZipOutputStream(new FileOutputStream(zipfullPath)); 103 zip.setEncoding("gbk"); 104 105 for(String fullPath:fileFullPaths) { 106 logger.info("【createZip:fullPath】:==>" + fullPath); 107 108 if(StringUtil.isNullOrEmpty(fullPath)) { 109 continue; 110 } 111 112 //創建文件 113 File file = new File(fullPath); 114 String fileName = file.getName(); 115 116 //讀文件流 117 inputStream = new BufferedInputStream(new FileInputStream(file)); 118 byte[] buffer = new byte[inputStream.available()]; 119 inputStream.read(buffer); 120 inputStream.close(); 121 122 //將讀取的文件輸出到zip中 123 zip.putNextEntry(new ZipEntry(fileName)); 124 zip.write(buffer); 125 zip.closeEntry(); 126 } 127 128 } catch (Exception e) { 129 e.printStackTrace(); 130 } finally { 131 try { 132 if (inputStream != null) { 133 inputStream.close(); 134 } 135 } catch (Exception e) { 136 e.printStackTrace(); 137 } 138 139 try { 140 if (zip != null) { 141 zip.close(); 142 } 143 } catch (Exception e) { 144 e.printStackTrace(); 145 } 146 147 } 148 } 149 150 /** 151 * 生成的zip文件帶子文件夾(全局可用) 152 * @param zipfullPath 壓縮后的zip文件全路徑 153 * @param fileFullPath 壓縮前的文件全路徑 154 * @param isKeepDirStr 是否保留原來的目錄結構,true:保留目錄結構; false:所有文件跑到壓縮包根目錄下(注意:不保留目錄結構可能會出現同名文件,會壓縮失敗) 155 */ 156 public static void createZip(String zipfullPath,String fileFullPath,boolean isKeepDirStr) { 157 InputStream inputStream = null; 158 ZipOutputStream zip = null; 159 160 try { 161 zip = new ZipOutputStream(new FileOutputStream(zipfullPath)); 162 zip.setEncoding("gbk"); 163 164 File file = new File(fileFullPath); 165 166 compressZip(inputStream,zip,file, file.getName(), isKeepDirStr);//遞歸壓縮 167 168 } catch (Exception e) { 169 e.printStackTrace(); 170 } finally { 171 try { 172 if (inputStream != null) { 173 inputStream.close(); 174 } 175 } catch (Exception e) { 176 e.printStackTrace(); 177 } 178 179 try { 180 if (zip != null) { 181 zip.close(); 182 } 183 } catch (Exception e) { 184 e.printStackTrace(); 185 } 186 187 } 188 } 189 190 /** 191 * 遞歸壓縮方法(僅限於此類中用於壓縮zip文件) 192 * @param inputStream 輸入流 193 * @param zip zip輸出流 194 * @param sourceFile 源文件 195 * @param fileName 文件夾名或文件名 196 * @param isKeepDirStr 是否保留原來的目錄結構,true:保留目錄結構; false:所有文件跑到壓縮包根目錄下(注意:不保留目錄結構可能會出現同名文件,會壓縮失敗) 197 * @throws Exception 198 */ 199 private static void compressZip(InputStream inputStream,ZipOutputStream zip, File sourceFile, String fileName,boolean isKeepDirStr) throws Exception{ 200 logger.info("【compressZip:sourceFile】:==>" + sourceFile.getPath()); 201 logger.info("【compressZip:fileName】:==>" + fileName); 202 203 if(sourceFile.isFile()){ 204 //讀文件流 205 inputStream = new BufferedInputStream(new FileInputStream(sourceFile)); 206 byte[] buffer = new byte[inputStream.available()]; 207 inputStream.read(buffer); 208 inputStream.close(); 209 210 //將讀取的文件輸出到zip中 211 zip.putNextEntry(new ZipEntry(fileName)); 212 zip.write(buffer); 213 zip.closeEntry(); 214 } else { 215 File[] listFiles = sourceFile.listFiles(); 216 if(listFiles == null || listFiles.length == 0){ 217 // 需要保留原來的文件結構時,需要對空文件夾進行處理 218 if(isKeepDirStr){ 219 zip.putNextEntry(new ZipEntry(fileName + "/"));//空文件夾的處理 220 zip.closeEntry();// 沒有文件,不需要文件的copy 221 } 222 }else { 223 for (File file : listFiles) { 224 // 判斷是否需要保留原來的文件結構,注意:file.getName()前面需要帶上父文件夾的名字加一斜杠,不然最后壓縮包中就不能保留原來的文件結構,即:所有文件都跑到壓縮包根目錄下了 225 if (isKeepDirStr) { 226 compressZip(inputStream,zip,file, fileName + "/" + file.getName(),isKeepDirStr); 227 } else { 228 compressZip(inputStream,zip, file, file.getName(),isKeepDirStr); 229 } 230 } 231 } 232 } 233 } 234 235 /** 236 * 下載生成的文件(全局可用) 237 * @param fullPath 全路徑 238 * @param response 239 */ 240 public static void downLoadFile(String fullPath, HttpServletResponse response) { 241 logger.info("【downLoadFile:fullPath】:==>" + fullPath); 242 243 InputStream inputStream = null; 244 OutputStream outputStream = null; 245 246 try { 247 //創建文件 248 File file = new File(fullPath); 249 String fileName = file.getName(); 250 251 //讀文件流 252 inputStream = new BufferedInputStream(new FileInputStream(file)); 253 byte[] buffer = new byte[inputStream.available()]; 254 inputStream.read(buffer); 255 256 //清空響應 257 response.reset(); 258 response.setCharacterEncoding("UTF-8"); 259 response.setContentType("application/octet-stream; charset=utf-8"); 260 // response.setContentType("application/msword"); 261 response.setHeader("Content-Disposition","attachment; filename=" + new String(fileName.getBytes(), "ISO8859-1")); 262 response.setHeader("Content-Length", "" + file.length()); 263 264 //寫文件流 265 outputStream = new BufferedOutputStream(response.getOutputStream()); 266 outputStream.write(buffer); 267 outputStream.flush(); 268 } catch (Exception e) { 269 e.printStackTrace(); 270 } finally { 271 try { 272 if (outputStream != null) { 273 outputStream.close(); 274 } 275 } catch (Exception e) { 276 e.printStackTrace(); 277 } 278 try { 279 if (inputStream != null) { 280 inputStream.close(); 281 } 282 } catch (Exception e) { 283 e.printStackTrace(); 284 } 285 286 } 287 } 288 289 /** 290 * 下載網絡文件到本地(主要用於下載簡歷附件) 291 * @param urlAddress 網絡url地址,為空時直接返回 292 * @param fileFullPath 文件全路徑 293 */ 294 public static void createFromUrl(String urlAddress,String fileFullPath) { 295 logger.info("【service:開始下載網絡文件】:==> 網上文件地址:" + urlAddress + "文件保存路徑:" + fileFullPath); 296 297 if(StringUtil.isNullOrEmpty(urlAddress)) { 298 return ; 299 } 300 301 DataInputStream dataInputStream = null; 302 FileOutputStream fileOutputStream =null; 303 try { 304 305 URL url = new URL(urlAddress); 306 307 dataInputStream = new DataInputStream(url.openStream());//打開網絡輸入流 308 309 //創建文件 310 File file = new File(fileFullPath); 311 // 如果輸出目標文件夾不存在,則創建 312 if (!file.getParentFile().exists()) { 313 file.getParentFile().mkdirs(); 314 } 315 316 fileOutputStream = new FileOutputStream(file);//建立一個新的文件 317 318 byte[] buffer = new byte[1024]; 319 int length; 320 321 while((length = dataInputStream.read(buffer))>0){//開始填充數據 322 fileOutputStream.write(buffer,0,length); 323 } 324 325 fileOutputStream.flush(); 326 } catch (Exception e) { 327 e.printStackTrace(); 328 } finally { 329 try { 330 if(dataInputStream!=null) { 331 dataInputStream.close(); 332 } 333 } catch (IOException e) { 334 e.printStackTrace(); 335 } 336 337 try { 338 if(fileOutputStream!=null) { 339 fileOutputStream.close(); 340 } 341 } catch (IOException e) { 342 e.printStackTrace(); 343 } 344 } 345 } 346 347 /** 348 * 從網上或本地獲得圖片的base64碼(主要用於插入生成word中的圖片) 349 * @param urlAddress 網絡路徑,二選一,目前有問題 350 * @param pathAddress 本地路徑,二選一 351 * @return 返回base64碼或null 352 */ 353 public static String getImageBase(String urlAddress,String pathAddress) { 354 byte[] buffer = null; 355 InputStream inputStream = null; 356 String imageCodeBase64 = null; 357 358 try { 359 if(!StringUtil.isNullOrEmpty(urlAddress)){ 360 URL url = new URL(urlAddress); 361 inputStream = new DataInputStream(url.openStream());//打開網絡輸入流 362 buffer = new byte[inputStream.available()]; 363 inputStream.read(buffer); 364 }else if(!StringUtil.isNullOrEmpty(pathAddress)){ 365 inputStream = new BufferedInputStream(new FileInputStream(new File(pathAddress)));//讀文件流 366 buffer = new byte[inputStream.available()]; 367 inputStream.read(buffer); 368 }else { 369 return null; 370 } 371 372 imageCodeBase64 = Base64.encodeBase64String(buffer); 373 // System.out.println(imageCodeBase64); 374 }catch (Exception e) { 375 e.printStackTrace(); 376 }finally { 377 try { 378 if(inputStream!=null) { 379 inputStream.close(); 380 } 381 } catch (IOException e) { 382 e.printStackTrace(); 383 } 384 } 385 return imageCodeBase64; 386 } 387 388 389 390 391 }
六、調用處代碼如下
邏輯:循環開始 ==>
取出簡歷數據封裝到Map中 ==> 生成word文件到磁盤 ==> 下載附件等到磁盤 ==> 將word文件、下載好的文件 的全路徑名放入到路徑數組中
==> 循環中....
循環結束 ==>
根據路徑數組打包生成zip到磁盤 ==>
下載zip文件 ==>
刪除原文件和zip文件,下載完畢 ==>
1 @Transactional(rollbackFor=Exception.class) 2 @Override 3 public void exportWordResume(List<ResumeDelivery> resumeDeliveryList,int userId, HttpServletResponse response) throws Exception { 4 logger.info("【service:exportWordResume】:==> 服務層請求開始"); 5 6 String[] fileFullPaths = new String[resumeDeliveryList.size()];//文件全路徑數組 7 String[] folderFullPaths = new String[resumeDeliveryList.size()];//文件夾全路徑數組 8 String[] addUrls = new String[resumeDeliveryList.size()];//附件全路徑數組 9 String[] videoFullPaths = new String[resumeDeliveryList.size()];//視頻全路徑數組 10 11 boolean flag = false;//該批文件是否存在附件 12 String templateName = "jlmb.ftl";//模板名稱 13 Resume resume = null;//簡歷 14 Map<String, Object> map = null;//獲取數據信息 15 String fileName = null;//文件名稱:應聘者姓名+應聘職位名稱+簡歷唯一標識號+下載人ID 16 String zipFullPath = filePath + File.separator + "小馬HR_求職者簡歷下載_" +userId;////要壓縮的文件夾路徑 17 String folderFullPath = null;//子文件夾全路徑 18 String fileFullPath = null;//文件全路徑 19 String addFullPath = null;//附件全路徑 20 String addSuffix = null;//附件后綴 21 String videoFullPath = null;//視頻全路徑 22 String videoSuffix = null;//視頻后綴 23 String headImagePath = null;//頭像全路徑 24 25 String validString = null; 26 Map<Integer,String> validMap = new HashMap<>();//簡歷字串 key:resumeId,value:resumeId+positionName 27 28 int index = 1;//簡歷下載數 29 int count = 0;//循環次數 30 for(ResumeDelivery resumeDeliveryBean:resumeDeliveryList) { 31 count++; 32 33 logger.info("【service:循環投遞記錄】:==> " + count); 34 35 //判斷是否重復的簡歷不予下載 36 validString = resumeDeliveryBean.getResumeId() + resumeDeliveryBean.getPositionName(); 37 if(validString.equals(validMap.get(resumeDeliveryBean.getResumeId()))){ 38 logger.info("【重復簡歷】:==> " + validString); 39 continue; 40 }else { 41 validMap.put(resumeDeliveryBean.getResumeId(), validString); 42 } 43 44 Assert.notNull(resumeDeliveryBean.getResumeId(), "第" + count +"份簡歷投遞記錄不存在!投遞ID:" + resumeDeliveryBean.getId()); 45 resume = resumeMapper.selectByPrimaryKey(resumeDeliveryBean.getResumeId()); 46 Assert.notNull(resume, "第" + count +"份簡歷不存在!投遞ID:" + resumeDeliveryBean.getId()); 47 48 //隱藏手機號 49 if(resumeDeliveryBean.getStatus() != null 50 && (resumeDeliveryBean.getStatus() == 0 51 || resumeDeliveryBean.getStatus() == 2 52 || resumeDeliveryBean.getStatus() == 3)) { // 已投遞、已過期、已淘汰 ==>隱藏手機號 53 if(!StringUtil.isNullOrEmpty(resumeDeliveryBean.getMobile())) { 54 resume.setMobile(resume.getMobile().substring(0, 3) + "****" + resume.getMobile().substring(resume.getMobile().length() - 4)); 55 } 56 }else if(resumeDeliveryBean.getEmployStatus() != null 57 && (resumeDeliveryBean.getEmployStatus() == 2 58 || resumeDeliveryBean.getEmployStatus() == 4 59 || resumeDeliveryBean.getEmployStatus() == 10)) { // 不合適、申訴中、已終止 60 if(!StringUtil.isNullOrEmpty(resumeDeliveryBean.getMobile())) { 61 resume.setMobile(resume.getMobile().substring(0, 3) + "****" + resume.getMobile().substring(resume.getMobile().length() - 4)); 62 } 63 } 64 65 fileName = resume.getHunterName() + "_" + resumeDeliveryBean.getPositionName() + "_" + resume.getId()+"_" + userId; 66 folderFullPath = zipFullPath + File.separator + fileName; 67 fileFullPath = folderFullPath + File.separator + fileName + ".doc"; 68 addSuffix = StringUtil.isNullOrEmpty(resume.getEnclosureAddress()) ? "" : resume.getEnclosureAddress().substring(resume.getEnclosureAddress().lastIndexOf(".")); 69 addFullPath = folderFullPath + File.separator + fileName + "_附件"+ addSuffix; 70 videoSuffix = StringUtil.isNullOrEmpty(resume.getVideoAddress()) ? "" : resume.getVideoAddress().substring(resume.getVideoAddress().lastIndexOf(".")); 71 videoFullPath = folderFullPath + File.separator + fileName + "_個人視頻"+ videoSuffix; 72 headImagePath = folderFullPath + File.separator + fileName + "_頭像.jpg"; 73 74 WordUtil.createFromUrl(resume.getPictureAddress(), headImagePath);//先下載頭像到本地,再插入到word中 75 map = this.getResumeData(resume,headImagePath); 76 77 logger.info("【service:開始生成word文件】:==> 文件名:" + fileFullPath); 78 WordUtil.createWord(map, templateName, fileFullPath);//生成word文件 79 logger.info("【service:生成word文件 完畢】:==>"); 80 81 FileUtil.deleteFile(headImagePath);//刪除頭像圖片 82 83 WordUtil.createFromUrl(resume.getEnclosureAddress(), addFullPath);//下載附件 84 WordUtil.createFromUrl(resume.getVideoAddress(), videoFullPath);//下載視頻 85 86 87 //賦值 88 fileFullPaths[index - 1] = fileFullPath; 89 folderFullPaths[index - 1] = folderFullPath; 90 if(!StringUtil.isNullOrEmpty(addSuffix)) { 91 addUrls[index - 1] = addFullPath; 92 flag = true; 93 } 94 if(!StringUtil.isNullOrEmpty(videoSuffix)) { 95 videoFullPaths[index - 1] = videoFullPath; 96 flag = true; 97 } 98 99 index++; 100 if(index == 20) {//設置最多一次下載10份簡歷 101 break; 102 } 103 } 104 105 if(!flag) { 106 if(resumeDeliveryList.size()==1) { 107 logger.info("【打包下載一】:==>"); 108 109 WordUtil.downLoadFile(fileFullPaths[0], response);//下載單個word文件 110 FileUtil.deleteFile(fileFullPaths[0]); 111 }else { 112 logger.info("【打包下載二】:==>"); 113 114 String zipFileFullPath = zipFullPath + ".zip";//壓縮后的文件名 115 116 WordUtil.createZip(zipFileFullPath, fileFullPaths);//生成zip不帶附件不帶子文件夾 117 WordUtil.downLoadFile(zipFileFullPath, response);//下載zip文件 118 119 FileUtil.deleteFile(zipFileFullPath); 120 } 121 }else { 122 if(resumeDeliveryList.size()==1) { 123 logger.info("【打包下載三】:==>"); 124 125 String zipFileFullPath = folderFullPaths[0] + ".zip";//壓縮后的文件名 126 String[] newfileFullPaths = new String[]{fileFullPaths[0],addUrls[0],videoFullPaths[0]};//需要下載的文件 127 128 WordUtil.createZip(zipFileFullPath, newfileFullPaths);//生成zip帶附件不帶子文件夾 129 WordUtil.downLoadFile(zipFileFullPath, response);//下載zip文件 130 }else { 131 logger.info("【打包下載四】:==>"); 132 133 String zipFileFullPath = zipFullPath + ".zip";;//壓縮后的文件名 134 135 WordUtil.createZip(zipFileFullPath, zipFullPath , true);//生成zip帶附件 136 WordUtil.downLoadFile(zipFileFullPath, response);//下載zip文件 137 138 FileUtil.deleteFile(zipFileFullPath); 139 } 140 } 141 142 FileUtil.deleteFileDir(zipFullPath); 143 } 144 145 /** 146 * 簡歷信息轉Map 147 * @param resume 簡歷對象 148 * @param headImagePath 頭像全路徑 149 * @return 返回map集合 150 * @throws Exception 出生日期轉年齡可能會拋出異常 151 */ 152 public Map<String, Object> getResumeData(Resume resume,String headImagePath) throws Exception{ 153 Map<String, Object> map = new HashMap<>(); 154 map.put(Resume.EXPORT_HUNTER_NAME, resume.getHunterName()); 155 map.put(Resume.EXPORT_SEX_STR, resume.getSexStr()); 156 map.put(Resume.EXPORT_AGE, AgeUtil.getAgeByBirth(resume.getDateOfBirth()) + "歲"); 157 map.put(Resume.EXPORT_WORHING_LENGTH_STR, resume.getWorkingLengthStr()==null ? "" : resume.getWorkingLengthStr()); 158 map.put(Resume.EXPORT_MOBILE, resume.getMobile()); 159 map.put(Resume.EXPORT_CREDENTIALS, resume.getCredentials()); 160 map.put(Resume.EXPORT_INTRODUCE, resume.getIntroduce()); 161 map.put(Resume.EXPORT_PICTURE_ADDRESS, StringUtil.isNullOrEmpty(resume.getPictureAddress()) ? null : WordUtil.getImageBase(null, headImagePath));//頭像 162 163 map.put(Resume.EXPORT_INTENTION_POSITION, resume.getIntentionPosition()); 164 map.put(Resume.EXPORT_INTENTION_LOCALE_STR, resume.getIntentionLocaleStr()); 165 map.put(Resume.EXPORT_SALARY_UNIT_STR, resume.getSalaryExpectation()); 166 map.put(Resume.EXPORT_RESUME_STATUS_STR, resume.getResumeStatusStr()); 167 168 map.put(Resume.EXPORT_STUDY_BEGIN_END_DATE, null); 169 map.put(Resume.EXPORT_GRADUATE_SCHOOL, resume.getGraduateSchool()); 170 map.put(Resume.EXPORT_PROFESSION, resume.getProfession()); 171 map.put(Resume.EXPORT_EDUCATIONAL_BACKGROUND_STR, resume.getEducationalBackgroundStr()); 172 173 map.put(Resume.EXPORT_HONORS, resume.getHonors()); 174 175 if(resume.getResumeExperience()!=null && resume.getResumeExperience().size()>0) { 176 List<Map<String,Object>> list = new ArrayList<>(); 177 Map<String, Object> exprMap = null; 178 for(ResumeExperience re:resume.getResumeExperience()) { 179 exprMap = new HashMap<>(); 180 exprMap.put(ResumeExperience.EXPORT_COMPANY_NAME, re.getCompanyName()); 181 exprMap.put(ResumeExperience.EXPORT_POSITION, re.getPosition()); 182 exprMap.put(ResumeExperience.EXPORT_WORD_DESC, re.getWorkDesc()); 183 exprMap.put(ResumeExperience.EXPORT_WORK_BEGIN_END_DATE, (re.getStartDate().replace("-", "/") + "-" + re.getEndDate().replace("-", "/"))); 184 list.add(exprMap); 185 } 186 187 map.put(Resume.EXPORT_EXPERIENCE, list); 188 } 189 190 return map; 191 }
七、從測試環境下載后的簡歷如下
八、過程中出現的問題:
1、模板文件路徑找不到 ==> 相對路徑問題,檢查后解決;
2、空值字段報錯或顯示錯誤 ==> 工具類代碼中已解決;或修改.ftl文件中,字段接受時設置默認值;
3、多個工作經歷只顯示一個 ==> 數據傳值有誤,檢查后解決;
4、頭像不顯示 ==> 生成的圖片的base64位碼有誤,工具類代碼中已解決;
5、doc文件不生成 ==> 模板文件字段值有問題,檢查后解決;
6、下載速度問題 ==> 目前限制只能一次下載20個。