本文记录
首先需要准备一个导入模板的实体类
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; }
到此就结束了,逻辑的话就看自己的业务来定了
标签:java,Excel,private,导入,importUser,import,class From: https://www.cnblogs.com/Dshzs17/p/16975477.html