实现学生管理
新增学生
接口设计
请求路径:/admin/student
请求方法:POST
请求参数:请求头:Headers:"Content-Type": "application/json"
请求体:Body:
id 学生id
idNumber 学生身份证
name 名字
phone 电话号码
sex 性别
username 用户名
返回数据:Result
student表设计
字段名 | 数据类型 | 说明 | 备注 |
id | bigint | 主键 | 自增 |
name | varchar(32) | 姓名 | |
username | varchar(32) | 用户名 | 唯一 |
password | varchar(64) | 密码 | |
phone | varchar(11) | 手机号 | |
sex | varchar(2) | 性别 | |
id_number | varchar(18) | 身份证号 | |
status | Int | 账号状态 | 1正常 0锁定 |
create_time | Datetime | 创建时间 | |
update_time | datetime | 最后修改时间 | |
create_user | bigint | 创建人id | |
update_user | bigint | 最后修改人id |
代码开发
设计DTO类接收前端传来的参数
sems-pojo/src/main/java/com/ljc/dto/StudentDTO.java
package com.ljc.dto;
import lombok.Data;
import java.io.Serializable;
@Data
public class StudentDTO implements Serializable {
//学生id
private Long id;
//用户名
private String username;
//姓名
private String name;
//电话
private String phone;
//性别
private String sex;
//身份证号
private String idNumber;
}
controller层
sems-server/src/main/java/com/ljc/controller/student/StudentController.java
package com.ljc.controller.student;
import com.ljc.constant.JwtClaimsConstant;
import com.ljc.dto.StudentDTO;
import com.ljc.dto.StudentLoginDTO;
import com.ljc.entity.Student;
import com.ljc.properties.JwtProperties;
import com.ljc.result.Result;
import com.ljc.service.StudentService;
import com.ljc.utils.JwtUtil;
import com.ljc.vo.StudentLoginVO;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/admin/student")
@Slf4j
public class StudentController {
@Autowired
private StudentService studentService;
@Autowired
private JwtProperties jwtProperties;
/**
* 登录
*
* @param studentLoginDTO
* @return
*/
@ApiOperation("用户登录")
@PostMapping("/login")
public Result<StudentLoginVO> login(@RequestBody StudentLoginDTO studentLoginDTO) {
log.info("学生登录:{}", studentLoginDTO);
Student student = studentService.login(studentLoginDTO);
//登录成功后,生成jwt令牌
Map<String, Object> claims = new HashMap<>();
claims.put(JwtClaimsConstant.EMP_ID, student.getId());
String token = JwtUtil.createJWT(
jwtProperties.getAdminSecretKey(),
jwtProperties.getAdminTtl(),
claims);
StudentLoginVO studentLoginVO = StudentLoginVO.builder()
.id(student.getId())
.userName(student.getUsername())
.name(student.getName())
.token(token)
.build();
return Result.success(studentLoginVO);
}
/**
* 退出
*
* @return
*/
@ApiOperation("用户退出")
@PostMapping("/logout")
public Result<String> logout() {
return Result.success();
}
/**
* 新增学生
* @param studentDTO
* @return
*/
@PostMapping
@ApiOperation("新增学生")
public Result save(@RequestBody StudentDTO studentDTO){
//日志,现在进行的是新增学生功能
log.info("新增学生:{}", studentDTO);
//调用service层(处理层)的方法进行新增
studentService.save(studentDTO);
return Result.success();
}
}
Service层
sems-server/src/main/java/com/ljc/service/StudentService.java
package com.ljc.service;
import com.ljc.dto.StudentDTO;
import com.ljc.dto.StudentLoginDTO;
import com.ljc.entity.Student;
public interface StudentService {
/**
* 学生登录
* @param studentLoginDTO
* @return
*/
Student login(StudentLoginDTO studentLoginDTO);
/**
* 新增学生
* @param studentDTO
*/
void save(StudentDTO studentDTO);
}
ServiceImpl层
sems-server/src/main/java/com/ljc/service/impl/StudentServiceImpl.java
package com.ljc.service.impl;
import com.ljc.constant.MessageConstant;
import com.ljc.constant.PasswordConstant;
import com.ljc.constant.StatusConstant;
import com.ljc.context.BaseContext;
import com.ljc.dto.StudentDTO;
import com.ljc.dto.StudentLoginDTO;
import com.ljc.entity.Student;
import com.ljc.exception.AccountLockedException;
import com.ljc.exception.AccountNotFoundException;
import com.ljc.exception.PasswordErrorException;
import com.ljc.mapper.StudentMapper;
import com.ljc.service.StudentService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import java.time.LocalDateTime;
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentMapper studentMapper;
/**
* 学生登录
*
* @param studentLoginDTO
* @return
*/
public Student login(StudentLoginDTO studentLoginDTO) {
String username = studentLoginDTO.getUsername();
String password = studentLoginDTO.getPassword();
//1、根据用户名查询数据库中的数据
Student student = studentMapper.getByUsername(username);
//2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)
if (student == null) {
//账号不存在
throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
}
//密码比对
// 进行md5加密,然后再进行比对
password = DigestUtils.md5DigestAsHex(password.getBytes());
if (!password.equals(student.getPassword())) {
//密码错误
throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
}
if (student.getStatus() == StatusConstant.DISABLE) {
//账号被锁定
throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
}
//3、返回实体对象
return student;
}
/**
*
* 新增学生
* @param studentDTO
*/
@Override
public void save(StudentDTO studentDTO) {
//1. 创建一个学生对象
Student student = new Student();
//2. 将前端传后来的参数,即就是封装在DTO里面的数据转移到学生对象中
//调用对象属性拷贝,括号里面参数,前面的是需要传递的数据,后面的是接收的数据
BeanUtils.copyProperties(studentDTO,student);
//3. 补充student里面的数据,前端没有传递回来的
//3.1 前端没有传递账号状态,现在给设置账号状态:默认为正常,正常为1,异常为0;
//由于1太不美观了,创建一个常量类
/*student.setStatus(1);*/
student.setStatus(StatusConstant.ENABLE);
//3.2 设置密码:默认为123456,进行MD5加密
//密码也设置一个常量:PasswordConstant.DEFAULT_PASSWORD
/*student.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));*/
student.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));
//3.3 设置创建时间和修改时间: 为当前时间
student.setCreateTime(LocalDateTime.now());
student.setUpdateTime(LocalDateTime.now());
//3.4 设置创建人的id
student.setCreateUser(BaseContext.getCurrentId());
student.setUpdateUser(BaseContext.getCurrentId());
//4 调用mapper层数据,连接数据库,对数据库进行操作
studentMapper.insert(student);
}
}
mapper层
sems-server/src/main/java/com/ljc/mapper/StudentMapper.java
package com.ljc.mapper;
import com.ljc.entity.Student;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface StudentMapper {
/**
* 根据用户名查询学生
* @param username
* @return
*/
@Select("select * from student where username = #{username}")
Student getByUsername(String username);
/**
* 新增学生
* @param student
*/
@Insert("insert into student (name, username, password, phone, sex, id_number, create_time, update_time, create_user, update_user,status) " +
"values " +
"(#{name},#{username},#{password},#{phone},#{sex},#{idNumber},#{createTime},#{updateTime},#{createUser},#{updateUser},#{status})")
void insert(Student student);
}
补充代码
这里面有几个常量值,和一个ThreadLocal来获取jwt令牌里面的用户名
封装了 ThreadLocal 操作的工具类:
sems-common/src/main/java/com/ljc/context/BaseContext.java
package com.ljc.context;
public class BaseContext {
public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
public static void setCurrentId(Long id) {
threadLocal.set(id);
}
public static Long getCurrentId() {
return threadLocal.get();
}
public static void removeCurrentId() {
threadLocal.remove();
}
}
常量类
密码
sems-common/src/main/java/com/ljc/constant/PasswordConstant.java
package com.ljc.constant;
/**
* 密码常量
*/
public class PasswordConstant {
public static final String DEFAULT_PASSWORD = "123456";
}
补充用户名重复常量
sems-common/src/main/java/com/ljc/constant/MessageConstant.java
package com.ljc.constant;
/**
* 信息提示常量类
*/
public class MessageConstant {
public static final String PASSWORD_ERROR = "密码错误";
public static final String ACCOUNT_NOT_FOUND = "账号不存在";
public static final String ACCOUNT_LOCKED = "账号被锁定";
public static final String UNKNOWN_ERROR = "未知错误";
public static final String USER_NOT_LOGIN = "用户未登录";
public static final String CATEGORY_BE_RELATED_BY_SETMEAL = "当前分类关联了套餐,不能删除";
public static final String CATEGORY_BE_RELATED_BY_DISH = "当前分类关联了菜品,不能删除";
public static final String SHOPPING_CART_IS_NULL = "购物车数据为空,不能下单";
public static final String ADDRESS_BOOK_IS_NULL = "用户地址为空,不能下单";
public static final String LOGIN_FAILED = "登录失败";
public static final String UPLOAD_FAILED = "文件上传失败";
public static final String SETMEAL_ENABLE_FAILED = "套餐内包含未启售菜品,无法启售";
public static final String PASSWORD_EDIT_FAILED = "密码修改失败";
public static final String DISH_ON_SALE = "起售中的菜品不能删除";
public static final String SETMEAL_ON_SALE = "起售中的套餐不能删除";
public static final String DISH_BE_RELATED_BY_SETMEAL = "当前菜品关联了套餐,不能删除";
public static final String ORDER_STATUS_ERROR = "订单状态错误";
public static final String ORDER_NOT_FOUND = "订单不存在";
public static final String ALREADY_EXISTS = "已存在";
}
处理用户名重复的异常
sems-server/src/main/java/com/ljc/handler/GlobalExceptionHandler.java
package com.ljc.handler;
import com.ljc.constant.MessageConstant;
import com.ljc.exception.BaseException;
import com.ljc.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.sql.SQLIntegrityConstraintViolationException;
/**
* 全局异常处理器,处理项目中抛出的业务异常
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 捕获业务异常
* @param ex
* @return
*/
@ExceptionHandler
public Result exceptionHandler(BaseException ex){
log.error("异常信息:{}", ex.getMessage());
return Result.error(ex.getMessage());
}
/**
* 捕获用户名重复
* */
@ExceptionHandler
public Result exceptionHandler(SQLIntegrityConstraintViolationException ex){
//Duplicate entry 'zhangsan' for key 'employee.idx_username'
//获取异常信息
String massage = ex.getMessage();
//以” “分割异常信息;
if (massage.contains("Duplicate entry")){
String[] split = massage.split(" ");
String name = split[2];
String msg = name+ MessageConstant.ALREADY_EXISTS;//已存在已有常量,尽量避免字符串
return Result.error(msg);
}else {
return Result.error(MessageConstant.UNKNOWN_ERROR);
}
}
}
测试
完成后进入swagger界面测试一下
因为需要进行jwt令牌检测,所以
使用admin用户登录获取令牌
将合法的JWT令牌添加到全局参数中
检查一下添加上了没
然后开始测试
检查数据库添加上了没
学生分页查询
开发到这里我发现还得先开发前端,前端明确后,后端才有针对性,所以先完成前端代码。
麻了,前端一点不会啊,工期有点长了.....................