1. 程式人生 > 其它 >java 實現Excel匯入匯出功能

java 實現Excel匯入匯出功能

本文記錄

首先需要準備一個匯入模板的實體類

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;
    }

到此就結束了,邏輯的話就看自己的業務來定了