开始尝试从0写一个项目--后端(二)

news2025/2/24 21:05:32

实现学生管理

新增学生

接口设计

请求路径:/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令牌添加到全局参数中

检查一下添加上了没

然后开始测试

检查数据库添加上了没

学生分页查询

开发到这里我发现还得先开发前端,前端明确后,后端才有针对性,所以先完成前端代码。

麻了,前端一点不会啊,工期有点长了.....................

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1902112.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

N5 使用Gensim库训练Word2Vec模型

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊# 前言 前言 这周学习训练一个Word2Vec模型&#xff0c;并进行一些基本的词向量操作。 Word2Vec 模型 Word2Vec 是一种基于神经网络的词向量表示方法&#x…

零基础STM32单片机编程入门(八)定时器PWM输入实战含源码视频

文章目录 一.概要二.PWM输入框架图三.CubeMX配置一个PWM输入例程1.硬件准备2.创建工程3.调试 四.CubeMX工程源代码下载五.讲解视频链接地址六.小结 一.概要 脉冲宽度调制(PWM)&#xff0c;是英文“Pulse Width Modulation”的缩写&#xff0c;简称脉宽调制&#xff0c;是利用单…

数学建模算法目标规划

在人们的生产实践中&#xff0c;经常会遇到如何利用现有资源来安排生产&#xff0c;以取得最大经济 效益的问题。此类问题构成了运筹学的一个重要分支—数学规划&#xff0c;而线性规划(Linear Programming 简记 LP)则是数学规划的一个重要分支。特别是在计算机能处理成千上万个…

在电子表格中对多列数据去重

一、数据展示 二、代码 Sub 选中区域数据去重()Dim arr()Dim c, d, id Selection.Counti 0For Each c In SelectionIf c.Value <> "" ThenReDim Preserve arr(0 To i)arr(i) c.Valuei i 1End IfNextarr 一维去重(arr)i 0For Each c In Range("O2&…

35.哀家要长脑子了!--二分

模板 int check() {...} // 检查这个数是否符合相应的要求// 把区间[l, r] 划分成[l, mid] 和 [mid1, r] 时使用 // 找到数组中第一个大于等于某一值得元素或满足特定条件的第一个位置 int bsearch_1(int l, int r){int mid l r >> 1;while(l < r) {if(check(mi…

C++(Qt)-GIS开发-简易瓦片地图下载器

Qt-GIS开发-简易瓦片地图下载器 文章目录 Qt-GIS开发-简易瓦片地图下载器1、概述2、安装openssl3、实现效果4、主要代码4.1 算法函数4.2 瓦片地图下载url拼接4.3 多线程下载 5、源码地址6、参考 更多精彩内容&#x1f449;个人内容分类汇总 &#x1f448;&#x1f449;GIS开发 …

智慧景区解决方案PPT(89页)

智慧景区解决方案摘要 解决方案概述智慧景区解决方案旨在利用现代信息技术解决景区管理机构面临的保护与发展矛盾&#xff0c;推动服务职能转变&#xff0c;促进旅游产业跨越式发展&#xff0c;实现旅游经营增长和管理成本优化。 宏观政策背景国家旅游局发布的《“十三五”全国…

c++:struct和class的区别

C和C中struct的区别 (1)C中不支持成员函数&#xff08;只能通过函数指针成员变量间接支持&#xff09;&#xff0c;而C源生支持。 (2)C中不支持static成员&#xff0c;而C中支持。后面会详细讲&#xff0c;C static class是一个大知识点 (3)访问权限&#xff0c;C中默认public…

CS61B Data Structure-Jonathan Lecture2 using objects - OBJECTS METHODS

Recall String s1; // Step 1: declare a String variable s1 new String(); // Step 2: assign it a value, a new empty string objectString s2 new String(); // 1&2 combined今日知识点 situation: pointing to the same object s1 "Yow!";s2 s1; //…

电量监测与电量计基础知识

硬件之路学习笔记 ​-----前文导读----- ①、公众号主页点击发消息 ②、点击下方菜单获取系列文章 -----本文简介----- 主要内容包括&#xff1a; ①&#xff1a;简介 ②&#xff1a;省成本方式-电阻分压 ③&#xff1a;精确方式-电量计与阻抗跟踪技术 ----- 正文 ----…

线程同步66666

1. 概述 当有多个线程访问同一个共享资源&#xff08;临界资源&#xff09;时&#xff0c;且不允许同时访问&#xff0c;那么就需要线程同步。常见的线程同步方式&#xff1a;互斥锁、读写锁、条件变量、信号量。 2. 互斥锁 互斥锁的方式可以简单概括为&#xff1a;锁定操作…

第一天(点亮led灯+led灯闪烁)——Arduino uno R3 学习之旅

​ 常识: 一般智能手机的额定工作电流大约为200mA Arduino Uno板上I/0(输入/输出)引脚最大输出电流为40 mA Uno板控制器总的输出电流为200 mA 点亮LED灯 发光二极管介绍 发光二极管(Light Emitting Diode&#xff0c;简称LED)是一种能够将电能转化为光能的固态的半导体器件…

好消息!Stable Diffusion 3 允许商业化,很快开源更大版本模型

7月6日凌晨&#xff0c;著名开源大模型平台Stability AI修改了社区许可协议&#xff0c;最新发布的文生图模型Stable Diffusion 3 Medium允许商业化&#xff08;以下简称“SD3-M”&#xff09;。 如果企业、个人开发者每年收入低于100万美元&#xff08;大约726万元人民币&…

【漏洞复现】禅道——未授权登入(QVD-2024-15263)

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 禅道&#xff08;Zentao&#xff09;是一款开源的项目管理和协作…

AI文本转语音,再也不用担心视频配音了.

文章目录 简介代码实现调用开通百度付费包 简介 背景 我想要将文本,转为语音,然后配上图片,这样就可以很快生成一个视频. 可以说是配音吧,我还是比较喜欢通过代码来自动化.所以今天就来实现一下,同时做一下分享和记录.目标 通过python代码,自动将文本转为配音.平台 我选择了百…

MySQL:如何在已经使用的数据表中增加一个自动递增的字段

目录 一、需求 二、实现步骤 &#xff08;一&#xff09;数据表students &#xff08;二&#xff09;添加整型字段 &#xff08;三&#xff09;更新SID字段的值 1、使用用户定义的变量和JOIN操作 2、用SET语句和rownum变量 &#xff08;1&#xff09;操作方法 &#x…

法向量 - 平面上的法向量和曲面上的法向量

法向量 - 平面上的法向量和曲面上的法向量 flyfish 平面上的法向量 &#xff1a; 定义了一个平面 z 0 z 0 z0。 法向量是 (0, 0, 1)&#xff0c;表示垂直于平面的向上方向。 使用 quiver 函数在平面上绘制法向量。 曲面上的法向量 &#xff1a; 定义了一个曲面 z x 2…

硬件开发工具Arduino IDE

招聘信息共享社群 关联上篇文章乐鑫ESPRESSIF芯片开发简介 Arduino IDE&#xff08;集成开发环境&#xff09;是为Arduino硬件开发而设计的一款软件&#xff0c;它提供了一个易于使用的图形界面&#xff0c;允许用户编写、编辑、编译和上传代码到Arduino开发板。Arduino IDE的…

封装日历uniapp,只显示年月不显示日

默认展示最新日期 子组件 <template><view class"date-picker"><picker mode"date" fields"month" change"onDateChange" :value"selectedDate"><view class"picker">{{ selectedDate…

SQL-DCL(三)

一.DCL介绍 DCL英文全称是Data Control Language(数据库控制语言),用来管理数据库 用户,控制数据库的访问权限。 二.两个方面 1.数据库可以由那些用户访问 2.可以访问那些内容 三.DCL-管理用户 1.查询用户 USE mysql SELECT * FROM user 2.创建用户 CREATE USER…