java 實現Excel匯入匯出功能
阿新 • • 發佈:2022-12-12
本文記錄
首先需要準備一個匯入模板的實體類
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; import cn.iocoder.yudao.module.system.enums.DictTypeConstants; import com.alibaba.excel.annotation.ExcelProperty; import lombok.AllArgsConstructor;import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; /** * 使用者 Excel 匯入 VO */ @Data @Builder @AllArgsConstructor @NoArgsConstructor @Accessors(chain = false) // 設定 chain = false,避免使用者匯入有問題 public class UserImportExcelVO { @ExcelProperty("登入名稱") private String username; @ExcelProperty("使用者名稱稱") private String nickname; @ExcelProperty("部門編號") private Long deptId; @ExcelProperty("使用者郵箱") private String email; @ExcelProperty("手機號碼") private String mobile; @ExcelProperty(value = "使用者性別", converter = DictConvert.class) @DictFormat(DictTypeConstants.USER_SEX) private Integer sex; @ExcelProperty(value = "賬號狀態", converter = DictConvert.class) @DictFormat(DictTypeConstants.COMMON_STATUS) private Integer status; }
有了實體就可以直接寫介面了
@GetMapping("/get-import-template") @ApiOperation("獲得匯入使用者模板") public void importTemplate(HttpServletResponse response) throws IOException { // 手動建立匯出 demo List<UserImportExcelVO> list = Arrays.asList( UserImportExcelVO.builder().username("admin").deptId(1L).email("[email protected]").mobile("15601691300") .nickname("超級管理員").status(CommonStatusEnum.ENABLE.getStatus()).sex(SexEnum.MALE.getSex()).build(), UserImportExcelVO.builder().username("test").deptId(2L).email("[email protected]").mobile("15601701300") .nickname("測試管理員").status(CommonStatusEnum.DISABLE.getStatus()).sex(SexEnum.FEMALE.getSex()).build() ); // 輸出 ExcelUtils.write(response, "使用者匯入模板.xls", "使用者列表", UserImportExcelVO.class, list); }
匯入模板完成,那麼接下來就是匯入了,使用者匯入,如果是有部門、角色這些存在,就需要把部門和角色這兩個欄位設定為必須存在,不然就會報錯
匯入這裡的返回根據自己來定,我這裡使用了三個list來封裝,一個更新、新增,還有一個失敗
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Builder; import lombok.Data; import java.util.List; import java.util.Map; @ApiModel("管理後臺 - 使用者匯入 Response VO") @Data @Builder public class UserImportRespVO { @ApiModelProperty(value = "建立成功的使用者名稱陣列", required = true) private List<String> createUsernames; @ApiModelProperty(value = "更新成功的使用者名稱陣列", required = true) private List<String> updateUsernames; @ApiModelProperty(value = "匯入失敗的使用者集合", required = true, notes = "key 為使用者名稱,value 為失敗原因") private Map<String, String> failureUsernames; }
檔案處理的工具類ExcelUtils
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URLEncoder; import java.util.List; /** * Excel 工具類 * * @author Dshzs月 */ public class ExcelUtils { /** * 將列表以 Excel 響應給前端 * * @param response 響應 * @param filename 檔名 * @param sheetName Excel sheet 名 * @param head Excel head 頭 * @param data 資料列表哦 * @param <T> 泛型,保證 head 和 data 型別的一致性 * @throws IOException 寫入失敗的情況 */ public static <T> void write(HttpServletResponse response, String filename, String sheetName, Class<T> head, List<T> data) throws IOException { // 輸出 Excel EasyExcel.write(response.getOutputStream(), head) .autoCloseStream(false) // 不要自動關閉,交給 Servlet 自己處理 .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基於 column 長度,自動適配。最大 255 寬度 .sheet(sheetName).doWrite(data); // 設定 header 和 contentType。寫在最後的原因是,避免報錯時,響應 contentType 已經被修改了 response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); response.setContentType("application/vnd.ms-excel;charset=UTF-8"); } public static <T> List<T> read(MultipartFile file, Class<T> head) throws IOException { return EasyExcel.read(file.getInputStream(), head, null) .autoCloseStream(false) // 不要自動關閉,交給 Servlet 自己處理 .doReadAllSync(); } }
匯入介面importExcel
@PostMapping("/import") @ApiOperation("匯入使用者") @ApiImplicitParams({ @ApiImplicitParam(name = "file", value = "Excel 檔案", required = true, dataTypeClass = MultipartFile.class), @ApiImplicitParam(name = "updateSupport", value = "是否支援更新,預設為 false", example = "true", dataTypeClass = Boolean.class) }) @PreAuthorize("@ss.hasPermission('system:user:import')") public CommonResult<UserImportRespVO> importExcel(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception { List<UserImportExcelVO> list = ExcelUtils.read(file, UserImportExcelVO.class); return success(userService.importUsers(list, updateSupport)); }
@Override @Transactional(rollbackFor = Exception.class) // 新增事務,異常則回滾所有匯入 public UserImportRespVO importUsers(List<UserImportExcelVO> importUsers, boolean isUpdateSupport) { if (CollUtil.isEmpty(importUsers)) { throw exception(USER_IMPORT_LIST_IS_EMPTY); } UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>()) .updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build(); importUsers.forEach(importUser -> { // 校驗,判斷是否有不符合的原因 try { checkCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(), importUser.getDeptId(), null); } catch (ServiceException ex) { respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage()); return; } // 判斷如果不存在,在進行插入 AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername()); if (existUser == null) { userMapper.insert(UserConvert.INSTANCE.convert(importUser) .setPassword(encodePassword(userInitPassword)).setPostIds(new HashSet<>())); // 設定預設密碼及空崗位編號陣列 respVO.getCreateUsernames().add(importUser.getUsername()); return; } // 如果存在,判斷是否允許更新 if (!isUpdateSupport) { respVO.getFailureUsernames().put(importUser.getUsername(), USER_USERNAME_EXISTS.getMsg()); return; } AdminUserDO updateUser = UserConvert.INSTANCE.convert(importUser); updateUser.setId(existUser.getId()); userMapper.updateById(updateUser); respVO.getUpdateUsernames().add(importUser.getUsername()); }); return respVO; }
到此就結束了,邏輯的話就看自己的業務來定了