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

实现学生管理

新增学生

接口设计

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

检查一下添加上了没

然后开始测试

检查数据库添加上了没

学生分页查询

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VideoAgent——使用大规模语言模型作为代理来理解长视频

概述 论文地址&#xff1a;https://arxiv.org/pdf/2403.10517 本研究引入了一个新颖的基于代理的系统&#xff0c;名为 VideoAgent。该系统以大规模语言模型为核心&#xff0c;负责识别关键信息以回答问题和编辑视频。VideoAgent 在具有挑战性的 EgoSchema 和 NExT-QA 基准上进…

MySQL架构和工作流程

引言&#xff1a;MySQL执行一条sql语句期间发生了什么&#xff1f; 想要搞清楚这个问题&#xff0c;我们必须了解MySQL的体系结构和工作流程 一、MySQL体系结构 MySQL由以下几个部分组成 一、server层 1.MySQL Connnectors连接器&#xff0c;MySQL的连接池组件&#xff0c;…

【vue组件库搭建05】vitePress中使用vue/antd/demo预览组件

一、vitepress使用vue及antd组件 1.安装antd之后在docs\.vitepress\theme\index.ts引入文件 // https://vitepress.dev/guide/custom-theme import { h } from vue import type { Theme } from vitepress import DefaultTheme from vitepress/theme import ./style.css impor…

React 19 竞态问题解决

竞态问题/竞态条件 指的是&#xff0c;当我们在交互过程中&#xff0c;由于各种原因导致同一个接口短时间之内连续发送请求&#xff0c;后发送的请求有可能先得到请求结果&#xff0c;从而导致数据渲染出现预期之外的错误。 因为防止重复执行可以有效的解决竞态问题&#xff0…

试用笔记之-汇通Exe可执行文件之pe分析

首先下载汇通Exe可执行文件之pe分析 http://www.htsoft.com.cn/download/pedump.rar

苹果笔记本能玩网页游戏吗 苹果电脑玩steam游戏怎么样 苹果手机可以玩游戏吗 mac电脑安装windows

苹果笔记本有着优雅的机身、强大的性能&#xff0c;每次更新迭代都备受用户青睐。但是&#xff0c;当需要使用苹果笔记本进行游戏时&#xff0c;很多人会有疑问&#xff1a;苹果笔记本能玩网页游戏吗&#xff1f;苹果笔记本适合打游戏吗&#xff1f;本文将讨论这两个话题&#…

数据集 | 人脸公开数据集的介绍及下载地址

本文介绍了人脸相关算法的数据集。 1.人脸数据集详情 1.1.Labeled Faces in the Wild (LFW) 论文 下载地址&#xff1a;LFW Face Database : Main (umass.edu) 是目前人脸识别的常用测试集&#xff0c;其中提供的人脸图片均来源于生活中的自然场景&#xff0c;因此识别难度会…

Google Play上架:恶意软件、移动垃圾软件和行为透明度详细解析和解决办法 (一)

近期整理了许多开发者的拒审邮件和内容,也发现了许多问题,今天来说一下关于恶意软件这类拒审的问题。 目标邮件如下: 首先说一下各位小伙伴留言私信的一个方法,提供你的拒审邮件和时间,尽可能的详细,这样会帮助我们的团队了解你们的问题,去帮助小伙伴么解决问题。由于前…

【CUDA】 扫描 Scan

Scan Scan操作是许多应用程序中常见的操作。扫描操作采用一个二元运算符⊕和一个输入数组并计算输出数组如下&#xff1a; [x0,(x0⊕x1),…,( x0⊕x1⊕…..⊕xn-1)] 分层扫描和多种Scan算法介绍 Kogge-Stones Algorithm Kogge-Stones Algorithm最初是为设计快速加法电路而发…

【pytorch19】交叉熵

分类问题的loss MSECross Entropy LossHinge Loss &#xff08;SVN用的比较多&#xff09; ∑ i m a x ( 0 , 1 − y i ∗ h θ ( x i ) ) \sum_imax(0,1-y_i*h_\theta(x_i)) ∑i​max(0,1−yi​∗hθ​(xi​)) Entropy&#xff08;熵&#xff09; Uncertainty&#xff08;…

解决obsidian加粗中文字体显示不突出的问题

加粗字体显示不突出的原因&#xff1a;默认字体的加粗版本本来就不突出 解决方法&#xff1a;改成显示突出的类型Microsoft YaHei UI 【效果】 修改前&#xff1a;修改后&#xff1a; 其他方法&#xff1a; 修改css&#xff08;很麻烦&#xff0c;改半天也不一定奏效&#…

容器:stack

以下是关于stack容器的一些总结&#xff1a; stack容器比较简单&#xff0c;主要包括&#xff1a; 1、构造函数&#xff1a;stack [staName] 2、添加、删除元素: push() 、pop() 3、获取栈顶元素&#xff1a;top() 4、获取栈的大小&#xff1a;size() 5、判断栈是否为空&#x…

Codeforces Round 903 (Div. 3)A~F

A.Dont Try to Count 输入样例&#xff1a; 12 1 5 a aaaaa 5 5 eforc force 2 5 ab ababa 3 5 aba ababa 4 3 babb bbb 5 1 aaaaa a 4 2 aabb ba 2 8 bk kbkbkbkb 12 2 fjdgmujlcont tf 2 2 aa aa 3 5 abb babba 1 19 m mmmmmmmmmmmmmmmmmmm输出样例&#xff1a; 3 1 2 -1 1 0…

django之url路径

方式一&#xff1a;path 语法&#xff1a;<<转换器类型:自定义>> 作用&#xff1a;若转换器类型匹配到对应类型的数据&#xff0c;则将数据按照关键字传参的方式传递给视图函数 类型&#xff1a; str: 匹配除了”/“之外的非空字符串。 /test/zvxint: 匹配0或任何…

【IO】文件操作

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 文件1.1 认识文件1.2 分清操作的是内存还是硬盘1.3 路径1.3.1 目录结构1.3.2 相对和绝对路径 1.4 文本文件…

计算机网络——数据链路层(以太网扩展、虚拟局域网、高速以太网)

在许多情况下&#xff0c;我们希望把以太网的覆盖范围扩展。本节先讨论在物理层把以太网扩展&#xff0c;然后讨论在数据链路层把以太网扩展。这种扩展的以太网在网络层看来仍然是一个网络。 在物理层扩展以太网 现在&#xff0c;扩展主机和集线器之间的距离的一种简单方法就是…

Spring源码十四:Spring生命周期

上一篇我们在Spring源码十三&#xff1a;非懒加载单例Bean中看到了Spring会在refresh方法中去调用我们的finishBeanFactoryInitialization方法去实例化&#xff0c;所有非懒加载器单例的bean。并实例化后的实例放到单例缓存中。到此我们refresh方法已经接近尾声。 Spring的生命…

【前端实现】在父组件中调用公共子组件:注意事项逻辑示例 + 将后端数组数据格式转换为前端对象数组形式 + 增加和删除行

【前端】在父组件中调用公共子组件的实现方法 写在最前面一、调用公共子组件子组件CommonRow.vue父组件ParentComponent.vue 二、实现功能1. 将后端数组数据格式转换为前端对象数组形式2. 增加和删除row 三、小结 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2…

【论文解读】AGENTLESS:揭开基于LLM的软件工程代理的神秘面纱,重塑软件工程自动化新基线

&#x1f4dc; 文献卡 英文题目: Agentless: Demystifying LLM-based Software Engineering Agents;作者: Chunqiu Steven Xia; Yinlin Deng; Soren Dunn; Lingming ZhangDOI: 10.48550/arXiv.2407.01489摘要翻译: 大型语言模型&#xff08;LLM&#xff09;的最新进展显著推进…

nginx(三)—从Nginx配置熟悉Nginx功能

一、 Nginx配置文件结构 ... #全局块events { #events块... }http #http块 {... #http全局块server #server块{ ... #server全局块location [PATTERN] #location块{...}location [PATTERN] {...}}server{...}... #http全局块 …