Leonezhurui 2 лет назад
Родитель
Сommit
9425e21236

+ 15 - 0
pom.xml

@@ -100,6 +100,21 @@
             <scope>runtime</scope>
         </dependency>
 
+        <!--excel依赖-->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>5.2.5</version>
+        </dependency>
+
+        <!--csv依赖-->
+        <dependency>
+            <groupId>com.opencsv</groupId>
+            <artifactId>opencsv</artifactId>
+            <version>5.9</version>
+        </dependency>
+
+
 
     </dependencies>
 

+ 45 - 2
src/main/java/com/njuzr/eaibackend/controller/UserController.java

@@ -13,6 +13,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.core.annotation.AuthenticationPrincipal;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
 /**
  * @author: Leonezhurui
@@ -34,7 +35,7 @@ public class UserController {
 
 
     /**
-     * 用户更新自己的用户信息(固定信息不可更改,例如真实姓名、邮箱、学号、角色等
+     * (学生、老师)更新自己的用户信息,固定信息不可更改,例如真实姓名、邮箱、学号、角色等
      * @param id
      * @param userDTO
      * @return
@@ -51,8 +52,14 @@ public class UserController {
         return MyResponse.error(400, "请求体中包含了不能更新的字段");
     }
 
+    /**
+     * (管理员或教师)可以查找具体某个学生
+     * @param id
+     * @param userDetails
+     * @return
+     */
     @GetMapping("/{id}")
-//    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_TEACHER')")
+    @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_TEACHER')")
     public MyResponse findUserById(@PathVariable Long id, @AuthenticationPrincipal UserDetails userDetails) {
         log.info("用户认证成功,解析出的UserDetails信息如下:"+userDetails.getAuthorities());
         UserVO userVO = userService.findById(id);
@@ -60,4 +67,40 @@ public class UserController {
         return MyResponse.success(userVO);
     }
 
+    /**
+     * (管理员)通过上传excel/csv文件,批量创建用户,文件必须含有字段信息:姓名、学号、邮箱
+     * @return
+     */
+    @PostMapping("/batch-upload")
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
+    public MyResponse batchCreateUsers(@RequestParam("file")MultipartFile file) {
+        String fileName = file.getOriginalFilename();
+
+        // 根据文件类型进行不同的处理
+        try {
+            if(fileName.endsWith(".xls") || fileName.endsWith(".xlsx")) {
+                userService.batchCreateUsersFromExcel(file);
+            } else if (fileName.endsWith(".csv")) {
+                userService.batchCreateUsersFromCsv(file);
+            }else {
+                return MyResponse.error(400, "文件类型不支持");
+            }
+        } catch (Exception e) {
+            log.error("上传文件失败,错误如下:"+e.getMessage());
+            return MyResponse.error(400, "上传文件失败:"+e.getMessage());
+        }
+
+        return MyResponse.success("上传成功");
+    }
+
+    /**
+     * (管理员)根据ID删除某个特定的用户
+     * @param userId
+     * @return
+     */
+    @DeleteMapping()
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
+    public MyResponse deleteById(@RequestParam Long userId) {
+        return MyResponse.success("删除成功");
+    }
 }

+ 5 - 0
src/main/java/com/njuzr/eaibackend/mapper/UserMapper.java

@@ -2,9 +2,12 @@ package com.njuzr.eaibackend.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.njuzr.eaibackend.po.User;
+import org.apache.ibatis.annotations.Insert;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Select;
 
+import java.util.List;
+
 /**
  * @author: Leonezhurui
  * @Date: 2024/2/15 - 08:59
@@ -17,4 +20,6 @@ public interface UserMapper extends BaseMapper<User> {
     User selectByOfficialNumber(String officialNumber);
 
     int updateUser(User user);
+
+    int batchInsert(List<User> users);
 }

+ 10 - 0
src/main/java/com/njuzr/eaibackend/service/UserService.java

@@ -3,7 +3,12 @@ package com.njuzr.eaibackend.service;
 import com.njuzr.eaibackend.dto.UserDTO;
 import com.njuzr.eaibackend.dto.UserRegisterDTO;
 import com.njuzr.eaibackend.vo.UserVO;
+import com.opencsv.exceptions.CsvValidationException;
 import org.springframework.security.core.userdetails.User;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.List;
 
 /**
  * @author: Leonezhurui
@@ -19,4 +24,9 @@ public interface UserService {
     UserVO findById(Long id);
 
     UserVO updateUser(Long id, UserDTO userDTO);
+
+    void batchCreateUsersFromExcel(MultipartFile file) throws Exception;
+
+    void batchCreateUsersFromCsv(MultipartFile file) throws Exception;
+
 }

+ 110 - 0
src/main/java/com/njuzr/eaibackend/service/impl/UserServiceImpl.java

@@ -9,15 +9,28 @@ import com.njuzr.eaibackend.po.User;
 import com.njuzr.eaibackend.service.UserService;
 import com.njuzr.eaibackend.utils.ModelMapperUtil;
 import com.njuzr.eaibackend.vo.UserVO;
+import com.opencsv.CSVReader;
+import com.opencsv.exceptions.CsvValidationException;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
 
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.List;
+import java.util.UUID;
 
 /**
  * @author: Leonezhurui
@@ -31,6 +44,8 @@ public class UserServiceImpl implements UserService {
 
     private final UserMapper userMapper;
 
+    private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+
     @Autowired
     public UserServiceImpl(UserMapper userMapper) {
         this.userMapper = userMapper;
@@ -91,4 +106,99 @@ public class UserServiceImpl implements UserService {
         }
         return null;
     }
+
+    /**
+     * 解析文件,批量创建用户。其中,文件必须包含姓名、邮箱、学号。
+     * @param file
+     * @return
+     */
+    @Override
+    public void batchCreateUsersFromExcel(MultipartFile file) throws Exception {
+        Workbook workbook = new XSSFWorkbook(file.getInputStream());
+        Sheet sheet = workbook.getSheetAt(0); // 默认只允许一张表
+        Row headerRow = sheet.getRow(0);
+        int nameCol = findColumnIndex(headerRow, "姓名");
+        int numberCol = findColumnIndex(headerRow, "学号");
+        int emailCol = findColumnIndex(headerRow, "邮箱");
+
+        List<User> users = new ArrayList<>();
+
+        for (Row row : sheet) {
+            if (row.getRowNum() == 0) continue; // 跳过表头
+
+            User user = new User();
+            user.setName(row.getCell(nameCol).getStringCellValue());
+            user.setOfficialNumber(row.getCell(numberCol).getStringCellValue());
+            user.setOfficialEmail(row.getCell(emailCol).getStringCellValue());
+
+            // 随机生成密码,并使用BCryptPasswordEncoder加密密码
+            String randomPassword = UUID.randomUUID().toString();
+            String encodedPassword = passwordEncoder.encode(randomPassword);
+            user.setPassword(encodedPassword);
+
+            users.add(user);
+        }
+
+        int res = userMapper.batchInsert(users);
+        if (res == 0) throw new MyException(500, "批量创建失败");
+    }
+
+    @Override
+    public void batchCreateUsersFromCsv(MultipartFile file) throws Exception {
+        CSVReader csvReader = new CSVReader(new InputStreamReader(file.getInputStream()));
+        String[] header = csvReader.readNext();
+        int nameCol = findColumnIndex(header, "姓名");
+        int numberCol = findColumnIndex(header, "学号");
+        int emailCol = findColumnIndex(header, "邮箱");
+
+        List<User> users = new ArrayList<>();
+        String[] nextRecord;
+        while ((nextRecord = csvReader.readNext()) != null) {
+            User user = new User();
+            user.setName(nextRecord[nameCol]);
+            user.setOfficialNumber(nextRecord[numberCol]);
+            user.setOfficialEmail(nextRecord[emailCol]);
+
+            // 随机生成密码,并使用BCryptPasswordEncoder加密密码
+            String randomPassword = UUID.randomUUID().toString();
+            String encodedPassword = passwordEncoder.encode(randomPassword);
+            user.setPassword(encodedPassword);
+
+            users.add(user);
+        }
+
+        int res = userMapper.batchInsert(users);
+        if (res == 0) throw new MyException(500, "批量创建失败");
+    }
+
+    private int findColumnIndex(Row headerRow, String columnName) {
+        for (Cell cell : headerRow) {
+            if (cell.getStringCellValue().trim().equalsIgnoreCase(columnName)) {
+                return cell.getColumnIndex();
+            }
+        }
+        return -1;
+    }
+
+    private int findColumnIndex(String[] header, String columnName) {
+        for (int i = 0; i < header.length; i++) {
+            if (header[i].trim().equalsIgnoreCase(columnName)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+//    private void processUsers(List<User> users) {
+//        for(User user: users) {
+//            // 随机生成密码,并使用BCryptPasswordEncoder加密密码
+//            String randomPassword = UUID.randomUUID().toString();
+//            String encodedPassword = passwordEncoder.encode(randomPassword);
+//            user.setPassword(encodedPassword);
+//        }
+//        int res = userMapper.batchInsert(users);
+//        if (res == 0) throw new MyException(500, "批量创建失败");
+//        // TODO 通过邮箱服务,将初始密码发送给指定邮箱
+//    }
+
 }

+ 7 - 0
src/main/resources/mapper/UserMapper.xml

@@ -24,4 +24,11 @@
         </set>
         WHERE id=#{id}
     </update>
+
+    <insert id="batchInsert" parameterType="list">
+        INSERT INTO users (name, official_number, official_email) VALUES
+        <foreach collection="list" item="user" index="index" separator=",">
+            (#{user.name}, #{user.officialNumber}, #{user.officialEmail})
+        </foreach>
+    </insert>
 </mapper>