From 461d9fc87ce632a17307bb80cbb5d0cd2208ffb1 Mon Sep 17 00:00:00 2001 From: Spark <2666652@gmail.com> Date: Sat, 12 Oct 2024 00:43:35 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E5=92=8C=E6=B3=A8=E5=86=8C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cc/aspark/controller/AdminController.java | 44 +++ .../java/cc/aspark/mapper/AdminMapper.java | 14 + .../java/cc/aspark/service/AdminService.java | 19 ++ .../aspark/service/impl/AdminServiceImpl.java | 87 ++++++ .../service/impl/StudentServiceImpl.java | 276 ++++++++++++++++++ .../src/main/resources/mapper/AdminMapper.xml | 19 ++ .../java/cc/aspark/TestApplicationTests.java | 13 - 7 files changed, 459 insertions(+), 13 deletions(-) create mode 100644 RollCallServer/src/main/java/cc/aspark/controller/AdminController.java create mode 100644 RollCallServer/src/main/java/cc/aspark/mapper/AdminMapper.java create mode 100644 RollCallServer/src/main/java/cc/aspark/service/AdminService.java create mode 100644 RollCallServer/src/main/java/cc/aspark/service/impl/AdminServiceImpl.java create mode 100644 RollCallServer/src/main/java/cc/aspark/service/impl/StudentServiceImpl.java create mode 100644 RollCallServer/src/main/resources/mapper/AdminMapper.xml delete mode 100644 RollCallServer/src/test/java/cc/aspark/TestApplicationTests.java diff --git a/RollCallServer/src/main/java/cc/aspark/controller/AdminController.java b/RollCallServer/src/main/java/cc/aspark/controller/AdminController.java new file mode 100644 index 0000000..386850a --- /dev/null +++ b/RollCallServer/src/main/java/cc/aspark/controller/AdminController.java @@ -0,0 +1,44 @@ +package cc.aspark.controller; + + +import cc.aspark.domain.dto.UserLoginDTO; +import cc.aspark.domain.dto.UserRegisterDTO; +import cc.aspark.domain.vo.UserLoginVO; +import cc.aspark.result.Result; +import cc.aspark.service.AdminService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +@Slf4j +@RestController +@RequestMapping("/admin") +@RequiredArgsConstructor +@Tag(name = "管理员表相关操作") +public class AdminController { + + private final AdminService adminService; + + @PostMapping("/login") + @Operation(summary = "用户登录") + public Result login(@RequestBody UserLoginDTO userLoginDTO) { + log.info("用户登录:{}", userLoginDTO); + UserLoginVO userLoginVO = adminService.login(userLoginDTO); + return Result.success(userLoginVO); + } + + @PostMapping("/register") + @Operation(summary = "用户注册") + public Result register(@RequestBody UserRegisterDTO userRegisterDTO) { + log.info("用户注册:{}", userRegisterDTO); + adminService.register(userRegisterDTO); + return Result.success(); + } + +} diff --git a/RollCallServer/src/main/java/cc/aspark/mapper/AdminMapper.java b/RollCallServer/src/main/java/cc/aspark/mapper/AdminMapper.java new file mode 100644 index 0000000..dd52e84 --- /dev/null +++ b/RollCallServer/src/main/java/cc/aspark/mapper/AdminMapper.java @@ -0,0 +1,14 @@ +package cc.aspark.mapper; + +import cc.aspark.domain.entity.Admin; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** +* @author night +* @description 针对表【admin(管理员信息表)】的数据库操作Mapper +* @createDate 2024-10-02 16:31:44 +* @Entity generator.domain.TbAdmin +*/ +public interface AdminMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/RollCallServer/src/main/java/cc/aspark/service/AdminService.java b/RollCallServer/src/main/java/cc/aspark/service/AdminService.java new file mode 100644 index 0000000..55b75a5 --- /dev/null +++ b/RollCallServer/src/main/java/cc/aspark/service/AdminService.java @@ -0,0 +1,19 @@ +package cc.aspark.service; + +import cc.aspark.domain.dto.UserLoginDTO; +import cc.aspark.domain.dto.UserRegisterDTO; +import cc.aspark.domain.entity.Admin; +import cc.aspark.domain.vo.UserLoginVO; +import com.baomidou.mybatisplus.extension.service.IService; + +/** +* @author night +* @description 针对表【tb_admin(管理员信息表)】的数据库操作Service +* @createDate 2024-10-02 16:31:44 +*/ +public interface AdminService extends IService { + + UserLoginVO login(UserLoginDTO userLoginDTO); + + void register(UserRegisterDTO userRegisterDTO); +} diff --git a/RollCallServer/src/main/java/cc/aspark/service/impl/AdminServiceImpl.java b/RollCallServer/src/main/java/cc/aspark/service/impl/AdminServiceImpl.java new file mode 100644 index 0000000..beb130b --- /dev/null +++ b/RollCallServer/src/main/java/cc/aspark/service/impl/AdminServiceImpl.java @@ -0,0 +1,87 @@ +package cc.aspark.service.impl; + +import cc.aspark.constant.MessageConstant; +import cc.aspark.domain.dto.UserLoginDTO; +import cc.aspark.domain.dto.UserRegisterDTO; +import cc.aspark.domain.entity.Admin; +import cc.aspark.domain.vo.UserLoginVO; +import cc.aspark.exception.AccountNotFoundException; +import cc.aspark.exception.LoginFailedException; +import cc.aspark.exception.PasswordErrorException; +import cc.aspark.mapper.AdminMapper; +import cc.aspark.properties.JwtProperties; +import cc.aspark.service.AdminService; +import cc.aspark.utils.JwtUtil; +import ch.qos.logback.core.util.StringUtil; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.crypto.SecureUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** +* @author night +* @description 针对表【admin(管理员信息表)】的数据库操作Service实现 +* @createDate 2024-10-02 16:31:44 +*/ +@Service +@RequiredArgsConstructor +@Slf4j +public class AdminServiceImpl extends ServiceImpl + implements AdminService { + + private final JwtProperties jwtProperties; + + @Override + public UserLoginVO login(UserLoginDTO userLoginDTO) { + + if (userLoginDTO == null || StringUtil.isNullOrEmpty(userLoginDTO.getUsername()) || StringUtil.isNullOrEmpty(userLoginDTO.getPassword())) { + throw new LoginFailedException(MessageConstant.INVALID_INPUT); + } + userLoginDTO.setPassword(SecureUtil.md5(userLoginDTO.getPassword())); + log.info(userLoginDTO.getPassword()); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Admin::getUsername, userLoginDTO.getUsername()); + Admin admin = baseMapper.selectOne(wrapper); + + if (admin == null) { + throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND); + } + + if (!admin.getPassword().equals(userLoginDTO.getPassword())) { + throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR); + } + + //登录成功后,生成jwt令牌 + Map claims = new HashMap<>(); + claims.put("id", admin.getId()); + claims.put("username", admin.getUsername()); + String token = JwtUtil.createJWT( + jwtProperties.getSecretKey(), + jwtProperties.getTtl(), + claims); + + UserLoginVO userLoginVO = BeanUtil.copyProperties(admin, UserLoginVO.class); + userLoginVO.setToken(token); + return userLoginVO; + } + + @Override + public void register(UserRegisterDTO userRegisterDTO) { + Admin admin = BeanUtil.copyProperties(userRegisterDTO, Admin.class); + admin.setPassword(SecureUtil.md5(admin.getPassword())); + admin.setUpdateTime(LocalDateTime.now()); + admin.setCreateTime(LocalDateTime.now()); + baseMapper.insert(admin); + } +} + + + + diff --git a/RollCallServer/src/main/java/cc/aspark/service/impl/StudentServiceImpl.java b/RollCallServer/src/main/java/cc/aspark/service/impl/StudentServiceImpl.java new file mode 100644 index 0000000..55209a8 --- /dev/null +++ b/RollCallServer/src/main/java/cc/aspark/service/impl/StudentServiceImpl.java @@ -0,0 +1,276 @@ +package cc.aspark.service.impl; + +import cc.aspark.constant.MessageConstant; +import cc.aspark.context.BaseContext; +import cc.aspark.domain.dto.PageQueryDTO; +import cc.aspark.domain.dto.StudentDTO; +import cc.aspark.domain.entity.Student; +import cc.aspark.exception.BaseException; +import cc.aspark.result.PageResult; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.poi.excel.ExcelReader; +import cn.hutool.poi.excel.ExcelUtil; +import cn.hutool.poi.excel.ExcelWriter; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.stream.Collectors; + +/** +* @author night +* @description 针对表【student(学生信息表)】的数据库操作Service实现 +* @createDate 2024-10-02 16:31:44 +*/ +@Service +@Slf4j +public class StudentServiceImpl extends ServiceImpl + implements StudentService { + + @Override + public void updateStu(StudentDTO studentDTO) { + Student student = BeanUtil.copyProperties(studentDTO, Student.class); + student.setUpdateTime(LocalDateTime.now()); + baseMapper.updateById(student); + } + + private void handleSort(LambdaQueryWrapper wrapper, String orderBy, String orderRule) { + if (orderBy == null || orderRule == null) { + wrapper.orderByAsc(Student::getNo); + return; + } + + // 使用Map存储字段与对应的getter方法 + Map> sortFieldMap = new HashMap<>(); + sortFieldMap.put("no", Student::getNo); + sortFieldMap.put("name", Student::getName); + sortFieldMap.put("gender", Student::getGender); + sortFieldMap.put("className", Student::getClassName); + sortFieldMap.put("points", Student::getPoints); + sortFieldMap.put("createTime", Student::getCreateTime); + sortFieldMap.put("updateTime", Student::getUpdateTime); + + SFunction sortField = sortFieldMap.get(orderBy); + if (sortField == null) { + throw new BaseException(MessageConstant.INVALID_INPUT); + } + + switch (orderRule.toUpperCase()) { + case "ASC" -> wrapper.orderByAsc(sortField); + case "DESC" -> wrapper.orderByDesc(sortField); + default -> throw new BaseException(MessageConstant.INVALID_INPUT); + } + } + + @Override + public PageResult page(PageQueryDTO pageQueryDTO) { + int page = Math.max(1, pageQueryDTO.getPage()); + int pageSize = Math.min(Math.max(1, pageQueryDTO.getPageSize()), 20); + + Page pageStu = new Page<>(page, pageSize); + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + + Boolean isExactQuery = pageQueryDTO.getExactQuery(); + if (isExactQuery == null || !isExactQuery) { + wrapper .eq(Student::getCreator, BaseContext.getCurrentId()) + .like(pageQueryDTO.getNo() != null, Student::getNo, pageQueryDTO.getNo()) + .like(pageQueryDTO.getName() != null, Student::getName, pageQueryDTO.getName()) + .eq(pageQueryDTO.getGender() != null, Student::getGender, pageQueryDTO.getGender()) + .like(pageQueryDTO.getClassName() != null, Student::getClassName, pageQueryDTO.getClassName()) + .between(pageQueryDTO.getCreateTimeStart() != null && pageQueryDTO.getCreateTimeEnd() != null, + Student::getCreateTime, pageQueryDTO.getCreateTimeStart(), pageQueryDTO.getCreateTimeEnd()) + .between(pageQueryDTO.getUpdateTimeStart() != null && pageQueryDTO.getUpdateTimeEnd() != null, + Student::getUpdateTime, pageQueryDTO.getUpdateTimeStart(), pageQueryDTO.getUpdateTimeEnd()); + } else { + wrapper .eq(Student::getCreator, BaseContext.getCurrentId()) + .eq(pageQueryDTO.getNo() != null, Student::getNo, pageQueryDTO.getNo()) + .eq(pageQueryDTO.getName() != null, Student::getName, pageQueryDTO.getName()) + .eq(pageQueryDTO.getGender() != null, Student::getGender, pageQueryDTO.getGender()) + .eq(pageQueryDTO.getClassName() != null, Student::getClassName, pageQueryDTO.getClassName()) + .between(pageQueryDTO.getCreateTimeStart() != null && pageQueryDTO.getCreateTimeEnd() != null, + Student::getCreateTime, pageQueryDTO.getCreateTimeStart(), pageQueryDTO.getCreateTimeEnd()) + .between(pageQueryDTO.getUpdateTimeStart() != null && pageQueryDTO.getUpdateTimeEnd() != null, + Student::getUpdateTime, pageQueryDTO.getUpdateTimeStart(), pageQueryDTO.getUpdateTimeEnd()); + } + + handleSort(wrapper, pageQueryDTO.getOrderBy(), pageQueryDTO.getOrderRule()); + + pageStu = baseMapper.selectPage(pageStu, wrapper); + + return new PageResult<>(pageStu.getTotal(), pageStu.getRecords()); + } + + @Override + public void save(StudentDTO studentDTO) { + Student student = BeanUtil.copyProperties(studentDTO, Student.class); + student.setUpdateTime(LocalDateTime.now()); + student.setCreateTime(LocalDateTime.now()); + student.setCreator(Integer.valueOf(BaseContext.getCurrentId().toString())); + log.info("{}", student); + baseMapper.insert(student); + } + + @Override + public Student rollCall() { + List studentList = this.list(); + + if (studentList.isEmpty()) { + throw new RuntimeException("学生列表为空"); + } + + // 找出最高积分,用于计算反向权重 + final double maxPoints = studentList.stream() + .mapToDouble(Student::getPoints) + .max() + .orElse(0.0) + 1.0; + + // 计算总的反向权重 + double totalInverseWeights = studentList.stream() + .mapToDouble(student -> maxPoints - student.getPoints()) + .sum(); + + // 生成一个0到总反向权重之间的随机数 + Random random = new Random(); + double randomValue = random.nextDouble() * totalInverseWeights; + + // 使用累加器方法选择学生 + double accumulatedWeight = 0; + for (Student student : studentList) { + // 计算该学生的反向权重 + double inverseWeight = maxPoints - student.getPoints(); + accumulatedWeight += inverseWeight; + if (accumulatedWeight >= randomValue) { + return student; + } + } + + // 以防万一,返回最后一个学生 + return studentList.get(studentList.size() - 1); + } + + @Override + public void importStudentsByExcel(MultipartFile file) { + try { + ExcelReader reader = ExcelUtil.getReader(file.getInputStream()); + reader .addHeaderAlias("学号", "no") + .addHeaderAlias("姓名", "name") + .addHeaderAlias("性别", "gender") + .addHeaderAlias("班级", "className") + .addHeaderAlias("积分", "credits") + .addHeaderAlias("创建时间", "createTime") + .addHeaderAlias("最后操作时间", "updateTime"); + List> rows = reader.readAll(); + LocalDateTime now = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + List studentList = rows.stream().map(row -> { + Student student = new Student(); + student.setNo(row.get("no").toString()); + student.setName(row.get("name").toString()); + student.setGender("男".equals(row.get("gender")) ? (short) 0 : (short) 1); + student.setClassName(row.get("className").toString()); + student.setCreator(Integer.valueOf(BaseContext.getCurrentId().toString())); + if (row.get("credits") == null) { + student.setPoints(0.00); + } else { + student.setPoints(Double.valueOf(row.get("credits").toString())); + } + + if (row.get("createTime") == null) { + student.setCreateTime(now); + } else { + String createTimeStr = row.get("createTime").toString(); + student.setCreateTime(LocalDateTime.parse(createTimeStr, formatter)); + } + + if (row.get("updateTime") == null) { + student.setUpdateTime(now); + } else { + String updateTimeStr = row.get("updateTime").toString(); + student.setUpdateTime(LocalDateTime.parse(updateTimeStr, formatter)); + } + return student; + }).toList(); + try { + baseMapper.insertOrUpdate(studentList); + } catch (Exception e) { + log.info(e.getMessage()); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void exportStudentsToExcel(HttpServletResponse response) { + try { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Student::getCreator, BaseContext.getCurrentId()); + List studentList = baseMapper.selectList(wrapper); + + // 创建一个Excel写入器 + ExcelWriter writer = ExcelUtil.getWriter(true); + + // 设置表头别名 + writer.addHeaderAlias("no", "学号"); + writer.addHeaderAlias("name", "姓名"); + writer.addHeaderAlias("gender", "性别"); + writer.addHeaderAlias("className", "班级"); + writer.addHeaderAlias("points", "积分"); + writer.addHeaderAlias("createTime", "创建时间"); + writer.addHeaderAlias("updateTime", "最后操作时间"); + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + // 将性别的数字转换为文字 + List> rows = studentList.stream().map(student -> { + Map row = new HashMap<>(); + row.put("no", student.getNo()); + row.put("name", student.getName()); + row.put("gender", student.getGender() == 0 ? "男" : "女"); + row.put("className", student.getClassName()); + row.put("points", student.getPoints()); + row.put("createTime", student.getCreateTime().format(formatter)); + row.put("updateTime", student.getUpdateTime().format(formatter)); + return row; + }).collect(Collectors.toList()); + + // 写入数据 + writer.write(rows, true); + + // 设置响应头 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); + response.setHeader("Content-Disposition", "attachment;filename=students.xlsx"); + + // 输出Excel文件 + ServletOutputStream out = response.getOutputStream(); + writer.flush(out, true); + writer.close(); + IoUtil.close(out); + + } catch (Exception e) { + log.error("导出Excel失败", e); + throw new BaseException(e.getMessage()); + } + } + + @Override + public void updatePoints(Integer id, Double points) { + Student student = baseMapper.selectById(id); + student.setPoints(student.getPoints() + points); + baseMapper.updateById(student); + } +} \ No newline at end of file diff --git a/RollCallServer/src/main/resources/mapper/AdminMapper.xml b/RollCallServer/src/main/resources/mapper/AdminMapper.xml new file mode 100644 index 0000000..b623a40 --- /dev/null +++ b/RollCallServer/src/main/resources/mapper/AdminMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + id,username,password, + create_time,update_time + + diff --git a/RollCallServer/src/test/java/cc/aspark/TestApplicationTests.java b/RollCallServer/src/test/java/cc/aspark/TestApplicationTests.java deleted file mode 100644 index eab8aeb..0000000 --- a/RollCallServer/src/test/java/cc/aspark/TestApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package cc.aspark; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class TestApplicationTests { - - @Test - void contextLoads() { - } - -}