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

news2025/1/19 8:01:51

创建文件的目录结构

利用这个界面创建

序号

名称

说明

1

SEMS

maven父工程,统一管理依赖版本,聚合其他子模块

2

sems-common

子模块,存放公共类,例如:工具类、常量类、异常类等

3

sems-pojo

子模块,存放实体类、VO、DTO等

4

sems-server

子模块,后端服务,存放配置文件、Controller、Service、Mapper等

配置pom文件

文件路径:SEMS\pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.3</version>
    </parent>
    <groupId>com.ljc</groupId>
    <artifactId>SEMS</artifactId>
    <packaging>pom</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <modules>
        <module>sems-common</module>
        <module>sems-pojo</module>
        <module>sems-server</module>
    </modules>

    <!--它定义了一系列项目依赖的版本号-->
    <properties>
        <mybatis.spring>2.2.0</mybatis.spring>
        <lombok>1.18.20</lombok>
        <fastjson>1.2.76</fastjson>
        <commons.lang>2.6</commons.lang>
        <druid>1.2.1</druid>
        <pagehelper>1.3.0</pagehelper>
        <aliyun.sdk.oss>3.10.2</aliyun.sdk.oss>
        <knife4j>3.0.2</knife4j>
        <aspectj>1.9.4</aspectj>
        <jjwt>0.9.1</jjwt>
        <jaxb-api>2.3.1</jaxb-api>
        <poi>3.16</poi>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!--mybatis的依赖-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring}</version>
            </dependency>

            <!--Lombok 是一个 Java 库,用于自动化生成如 getter、setter、toString 等方法-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok}</version>
            </dependency>

            <!--一个 Java 语言编写的高性能功能完善的 JSON 库-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>${fastjson}</version>
            </dependency>

            <!--一个包含大量静态方法的库,用于处理 Java 核心 API 中没有的常用功能-->
            <dependency>
                <groupId>commons-lang</groupId>
                <artifactId>commons-lang</artifactId>
                <version>${commons.lang}</version>
            </dependency>

            <!--阿里巴巴开源的数据库连接池-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid}</version>
            </dependency>

            <!--MyBatis 分页插件-->
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper-spring-boot-starter</artifactId>
                <version>${pagehelper}</version>
            </dependency>

            <!--Swagger 的增强 UI 实现,用于 API 文档生成-->
            <dependency>
                <groupId>com.github.xiaoymin</groupId>
                <artifactId>knife4j-spring-boot-starter</artifactId>
                <version>${knife4j}</version>
            </dependency>

            <!--AspectJ 是一个面向切面的编程(AOP)框架-->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>${aspectj}</version>
            </dependency>

            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>${aspectj}</version>
            </dependency>

            <!--Java JWT(JSON Web Tokens)库,用于生成和解析 JWT 令牌-->
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>${jjwt}</version>
            </dependency>

            <!--阿里云对象存储服务(OSS)的 Java SDK-->
            <dependency>
                <groupId>com.aliyun.oss</groupId>
                <artifactId>aliyun-sdk-oss</artifactId>
                <version>${aliyun.sdk.oss}</version>
            </dependency>

            <!--用于将 Java 类映射到 XML 表示-->
            <dependency>
                <groupId>javax.xml.bind</groupId>
                <artifactId>jaxb-api</artifactId>
                <version>${jaxb-api}</version>
            </dependency>

            <!-- poi -->
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>${poi}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>${poi}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

SEMS\sems-server\pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.ljc</groupId>
        <artifactId>SEMS</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>sems-server</artifactId>

    <dependencies>

        <dependency>
            <groupId>com.ljc</groupId>
            <artifactId>sems-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.ljc</groupId>
            <artifactId>sems-pojo</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
        </dependency>

        <!-- poi -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

SEMS\sems-pojo\pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.ljc</groupId>
        <artifactId>SEMS</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>sems-pojo</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
</project>

SEMS\sems-common\pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.ljc</groupId>
        <artifactId>SEMS</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>sems-common</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-json</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>
        <!--支持配置属性类,yml文件中可以提示配置项-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
        </dependency>
        <!--微信支付-->
        <dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-apache-httpclient</artifactId>
            <version>0.4.9</version>
        </dependency>
    </dependencies>
</project>

配置好后需要点击这个编译一下,显示成功才可继续后面的

配置git环境上传到仓库,反之代码丢失

在各自对应的结构下构建相应的目录结构

名称

说明

constant

存放相关常量类

context

存放上下文类

enumeration

项目的枚举类存储

exception

存放自定义异常类

json

处理json转换的类

properties

存放SpringBoot相关的配置属性类

result

返回结果类的封装

utils

常用工具类

名称

说明

Entity

实体,通常和数据库中的表对应

DTO

数据传输对象,通常用于程序中各层之间传递数据

VO

视图对象,为前端展示数据提供的对象

POJO

普通Java对象,只有属性和对应的getter和setter

名称

说明

config

存放配置类

controller

存放controller类

interceptor

存放拦截器类

mapper

存放mapper接口

service

存放service类

SemsApplication

启动类

配置application.yml文件

sems-server/src/main/resources/application.yml

server:
  port: 8080

spring:
  profiles:
    active: dev
  main:
    allow-circular-references: true
  datasource:
    druid:
      driver-class-name: ${ljc.datasource.driver-class-name}
      url: jdbc:mysql://${ljc.datasource.host}:${ljc.datasource.port}/${ljc.datasource.database}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
      username: ${ljc.datasource.username}
      password: ${ljc.datasource.password}

mybatis:
  #mapper配置文件
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.ljc.entity
  configuration:
    #开启驼峰命名
    map-underscore-to-camel-case: true

logging:
  level:
    com:
      sky:
        mapper: debug
        service: info
        controller: info

ljc:
  jwt:
    # 设置jwt签名加密时使用的秘钥
    admin-secret-key: kussm
    # 设置jwt过期时间
    admin-ttl: 7200000
    # 设置前端传递过来的令牌名称
    admin-token-name: token

sems-server/src/main/resources/application-dev.yml

ljc:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    host: localhost
    port: 3306
    database: sems
    username: root
    password: 8888

编写一些基础代码

1. 全局异常处理器,处理项目中抛出的业务异常

GlobalExceptionHandler(全局异常处理器)

sems-server\src\main\java\com\ljc\handler\GlobalExceptionHandler.java

package com.ljc.handler;

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;

/**
 * 全局异常处理器,处理项目中抛出的业务异常
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 捕获业务异常
     * @param ex
     * @return
     */
    @ExceptionHandler
    public Result exceptionHandler(BaseException ex){
        log.error("异常信息:{}", ex.getMessage());
        return Result.error(ex.getMessage());
    }

}

同时创建相关代码

BaseException(业务异常)

sems-common\src\main\java\com\ljc\exception\BaseException.java

package com.ljc.exception;

/**
 * 业务异常
 */
public class BaseException extends RuntimeException {

    public BaseException() {
    }

    public BaseException(String msg) {
        super(msg);
    }

}

Result(后端统一返回结果)

sems-common\src\main\java\com\ljc\result\Result.java

package com.ljc.result;

import lombok.Data;

import java.io.Serializable;

/**
 * 后端统一返回结果
 * @param <T>
 */
@Data
public class Result<T> implements Serializable {

    private Integer code; //编码:1成功,0和其它数字为失败
    private String msg; //错误信息
    private T data; //数据

    public static <T> Result<T> success() {
        Result<T> result = new Result<T>();
        result.code = 1;
        return result;
    }

    public static <T> Result<T> success(T object) {
        Result<T> result = new Result<T>();
        result.data = object;
        result.code = 1;
        return result;
    }

    public static <T> Result<T> error(String msg) {
        Result result = new Result();
        result.msg = msg;
        result.code = 0;
        return result;
    }

}

2. 配置类,注册web层相关组件JWT

注册自定义拦截器jwt

通过knife4j生成接口文档

设置静态资源映射

WebMvcConfiguration(配置类,注册web层相关组件)

sems-server\src\main\java\com\ljc\config\WebMvcConfiguration.java

package com.ljc.config;

import com.ljc.interceptor.JwtTokenAdminInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

/**
 * 配置类,注册web层相关组件
 */
@Configuration
@Slf4j
public class WebMvcConfiguration extends WebMvcConfigurationSupport {

    @Autowired
    private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;

    /**
     * 注册自定义拦截器
     *
     * @param registry
     */
    protected void addInterceptors(InterceptorRegistry registry) {
        log.info("开始注册自定义拦截器...");
        registry.addInterceptor(jwtTokenAdminInterceptor)
                .addPathPatterns("/admin/**")
                .excludePathPatterns("/admin/student/login");
    }

    /**
     * 通过knife4j生成接口文档
     * @return
     */
    @Bean
    public Docket docket() {
        ApiInfo apiInfo = new ApiInfoBuilder()
                .title("体育器材项目接口文档")
                .version("1.0")
                .description("体育器材项目接口文档")
                .build();
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.ljc.controller"))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }

    /**
     * 设置静态资源映射
     * @param registry
     */
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}

3. 相关联的jwt令牌校验的拦截器

JwtTokenAdminInterceptor

sems-server\src\main\java\com\ljc\interceptor\JwtTokenAdminInterceptor.java

package com.ljc.interceptor;

import com.ljc.constant.JwtClaimsConstant;
import com.ljc.properties.JwtProperties;
import com.ljc.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * jwt令牌校验的拦截器
 */
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtProperties jwtProperties;

    /**
     * 校验jwt
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断当前拦截到的是Controller的方法还是其他资源
        if (!(handler instanceof HandlerMethod)) {
            //当前拦截到的不是动态方法,直接放行
            return true;
        }

        //1、从请求头中获取令牌
        String token = request.getHeader(jwtProperties.getAdminTokenName());

        //2、校验令牌
        try {
            log.info("jwt校验:{}", token);
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
            Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
            log.info("当前员工id:", empId);
            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //4、不通过,响应401状态码
            response.setStatus(401);
            return false;
        }
    }
}

4. 常量类(后面用)

JwtClaimsConstant

sems-common/src/main/java/com/ljc/constant/JwtClaimsConstant.java

package com.ljc.constant;

public class JwtClaimsConstant {

    public static final String EMP_ID = "empId";
    public static final String USER_ID = "userId";
    public static final String PHONE = "phone";
    public static final String USERNAME = "username";
    public static final String NAME = "name";

}

MessageConstant

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 = "订单不存在";

}

StatusConstant

sems-common/src/main/java/com/ljc/constant/StatusConstant.java

package com.ljc.constant;

/**
 * 状态常量,启用或者禁用
 */
public class StatusConstant {

    //启用
    public static final Integer ENABLE = 1;

    //禁用
    public static final Integer DISABLE = 0;
}

5. 异常类

AccountLockedException

sems-common/src/main/java/com/ljc/exception/AccountLockedException.java

package com.ljc.exception;

/**
 * 账号被锁定异常
 */
public class AccountLockedException extends BaseException {

    public AccountLockedException() {
    }

    public AccountLockedException(String msg) {
        super(msg);
    }

}

AccountNotFoundException

sems-common/src/main/java/com/ljc/exception/AccountNotFoundException.java

package com.ljc.exception;

/**
 * 账号不存在异常
 */
public class AccountNotFoundException extends BaseException {

    public AccountNotFoundException() {
    }

    public AccountNotFoundException(String msg) {
        super(msg);
    }

}

PasswordErrorException

sems-common/src/main/java/com/ljc/exception/PasswordErrorException.java

package com.ljc.exception;

/**
 * 密码错误异常
 */
public class PasswordErrorException extends BaseException {

    public PasswordErrorException() {
    }

    public PasswordErrorException(String msg) {
        super(msg);
    }

}

6. 配置类

JwtProperties

sems-common/src/main/java/com/ljc/properties/JwtProperties.java

package com.ljc.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "ljc.jwt")
@Data
public class JwtProperties {

    /**
     * 管理端员工生成jwt令牌相关配置
     */
    private String adminSecretKey;
    private long adminTtl;
    private String adminTokenName;

    /**
     * 用户端微信用户生成jwt令牌相关配置
     */
    private String userSecretKey;
    private long userTtl;
    private String userTokenName;

}

7. 实用工具

JwtUtil(生成jwt)

sems-common/src/main/java/com/ljc/utils/JwtUtil.java

package com.ljc.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;

public class JwtUtil {
    /**
     * 生成jwt
     * 使用Hs256算法, 私匙使用固定秘钥
     *
     * @param secretKey jwt秘钥
     * @param ttlMillis jwt过期时间(毫秒)
     * @param claims    设置的信息
     * @return
     */
    public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) {
        // 指定签名的时候使用的签名算法,也就是header那部分
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        // 生成JWT的时间
        long expMillis = System.currentTimeMillis() + ttlMillis;
        Date exp = new Date(expMillis);

        // 设置jwt的body
        JwtBuilder builder = Jwts.builder()
                // 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
                .setClaims(claims)
                // 设置签名使用的签名算法和签名使用的秘钥
                .signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8))
                // 设置过期时间
                .setExpiration(exp);

        return builder.compact();
    }

    /**
     * Token解密
     *
     * @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个
     * @param token     加密后的token
     * @return
     */
    public static Claims parseJWT(String secretKey, String token) {
        // 得到DefaultJwtParser
        Claims claims = Jwts.parser()
                // 设置签名的秘钥
                .setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8))
                // 设置需要解析的jwt
                .parseClaimsJws(token).getBody();
        return claims;
    }

}

8. 阶段效果展示

现在就可以开始运行代码了

SemsApplication

sems-server/src/main/java/com/ljc/SemsApplication.java

package com.ljc;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableTransactionManagement //开启注解方式的事务管理
@Slf4j
public class SemsApplication {
    public static void main(String[] args) {
        SpringApplication.run(SemsApplication.class, args);
        log.info("server started");
    }
}

打开浏览器输入:http://localhost:8080/doc.html

可以看到通过knife4j生成的初步接口文档,后面慢慢完善接口

学生管理--登录

接口设计

请求路径:/admin/student/login

请求方式:POST

设计数据库

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

sql语句

DROP TABLE IF EXISTS student;
CREATE TABLE `employee` (
    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
    `name` varchar(32) COLLATE utf8_bin NOT NULL COMMENT '姓名',
    `username` varchar(32) COLLATE utf8_bin NOT NULL COMMENT '用户名',
    `password` varchar(64) COLLATE utf8_bin NOT NULL COMMENT '密码',
    `phone` varchar(11) COLLATE utf8_bin NOT NULL COMMENT '手机号',
    `sex` varchar(2) COLLATE utf8_bin NOT NULL COMMENT '性别',
    `id_number` varchar(18) COLLATE utf8_bin NOT NULL COMMENT '身份证号',
    `status` int NOT NULL DEFAULT '1' COMMENT '状态 0:禁用,1:启用',
    `create_time` datetime DEFAULT NULL COMMENT '创建时间',
    `update_time` datetime DEFAULT NULL COMMENT '更新时间',
    `create_user` bigint DEFAULT NULL COMMENT '创建人',
    `update_user` bigint DEFAULT NULL COMMENT '修改人',
    PRIMARY KEY (`id`),
    UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin COMMENT='员工信息';

INSERT INTO student VALUES (1,'管理员','admin','123456','13812312312','1','110101199001010047',1,'2022-02-15 15:51:20','2022-02-17 09:16:20',10,1);

设计接收和回传数据的DTO和VO结构以及和数据库对应的entity实体类

Student

sems-pojo/src/main/java/com/ljc/entity/Student.java

package com.ljc.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.time.LocalDateTime;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Serializable {
    private static final long serialVersionUID = 1L;

    private Long id;

    private String username;

    private String name;

    private String password;

    private String phone;

    private String sex;

    private String idNumber;

    private Integer status;

    //@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    //@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;

    private Long createUser;

    private Long updateUser;

}

StudentLoginDTO

sems-pojo/src/main/java/com/ljc/dto/StudentLoginDTO.java

package com.ljc.dto;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;

@Data
@ApiModel(description = "学生登录时传递的数据模型")
public class StudentLoginDTO implements Serializable {

    @ApiModelProperty("用户名")
    private String username;

    @ApiModelProperty("密码")
    private String password;
}

StudentLoginVO

sems-pojo/src/main/java/com/ljc/vo/StudentLoginVO.java

package com.ljc.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "学生登录返回的数据格式")
public class StudentLoginVO implements Serializable {
    @ApiModelProperty("主键值")
    private Long id;

    @ApiModelProperty("用户名")
    private String userName;

    @ApiModelProperty("姓名")
    private String name;

    @ApiModelProperty("jwt令牌")
    private String token;

}

设计真正业务的代码

controller层-StudentController

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.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 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
     */
    @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
     */
    @PostMapping("/logout")
    public Result<String> logout() {
        return Result.success();
    }
}

service层-StudentService

sems-server/src/main/java/com/ljc/service/StudentService.java

package com.ljc.service;

import com.ljc.dto.StudentLoginDTO;
import com.ljc.entity.Student;

public interface StudentService {

    /**
     * 学生登录
     * @param studentLoginDTO
     * @return
     */
    Student login(StudentLoginDTO studentLoginDTO);

}

service层-StudentServiceImpl

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.StatusConstant;
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.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@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);
        }

        //密码比对
        // TODO 后期需要进行md5加密,然后再进行比对
        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;
    }

}

mapper层-StudentMapper

sems-server/src/main/java/com/ljc/mapper/StudentMapper.java

package com.ljc.mapper;

import com.ljc.entity.Student;
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);

}

阶段结果展示

通过swagger测试

注意:我在运行中出现的一些问题:

基本就没什么问题了。

这样登录功能就搞定了!!!!!

目前为止整体结构

完善登录功能

学生表中的密码是明文存储,安全性太低

使用MD5加密方式对明文密码加密

”123456“进行MD5加密后结果为:

e10adc3949ba59abbe56e057f20f883e

进入数据库,修改密码为这个

修改代码

完整代码:

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.StatusConstant;
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.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

@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;
    }

}

初步完成这样

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

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

相关文章

前端Debugger时复制的JS对象字符转JSON对象

前端debugger时&#xff0c;复制的对象在控制台输出时是如下格式&#xff0c;需要转换为对象格式来进行验证操作 bridgeId : 4118 createBy : null createTime : "2023-03-24 10:35:26" createUserId : 1 具体实现代码&#xff1a; // 转换transform (text) {l…

数据库表导出到excel:前置知识3 项目封装的Quartz实现动态定时任务

参考网址 目标&#xff1a;定时任务持久化到数据库&#xff0c;动态调整数据库里保存的cron表达式使定时任务可以跟随变化。 从SYS_QUARTZ_JOB表(通过反射创建任务)和SYS_QUARTZ_LOG表(主要就是记录日志)构建两个对应的实体类&#xff1a;QuartzJob和QuartzLog 1.看表结构 …

云计算【第一阶段(26)】Linux网络设置

一、查看网络配置 1.查看网络接口信息ifconfig 查看所有活动的网络接口信息 2.ifconfig命令 查看指定网络接口信息 ifconfig 网络接口 &#xff08;1&#xff09;第一行&#xff1a;以太网卡的名字 ens33其中en代表以太网卡&#xff0c; centos6的是eth0&#xff0c; e…

什么是数字体验成熟度,以及数字成熟度的模型计算和实现方法

“开发成功的全渠道数字身份&#xff0c;并通过无缝的数字体验吸引广泛的受众。无论您身在何处&#xff0c;都可以加速数字化转型并促进业务增长。通过直观、全面的工具&#xff0c;并了解您个人的数字体验成熟度水平&#xff0c;超越不断增长的客户期望并超越竞争对手。今天就…

第二十条:与抽象类相比,优先选择接口

要定义多种实现的类型&#xff1a;JAVA有两种机制&#xff1a;接口和抽象类。这两种机制都支持为某些实例方法提供实现&#xff0c;但二者有个重要的区别&#xff1a;要实现由抽象类定义的类型&#xff0c;这个类必须是抽象类的子类。因为Java只允许单继承&#xff0c;对抽象类…

2025年中国国际新能源汽车技术零部件及服务展览会

中国国际新能源汽车技术零部件及服务展览会&#xff0c;从设计到制造、从使用到服务&#xff0c;精准“链”接新能源汽车全产业链的技术供应商和汽车制造商&#xff0c;专业面向新能源造车供应链的行业盛会。2024展会回顾&#xff1a;在展会的3天里&#xff0c;有62家车企核心供…

如何自动筛选螺丝不良品?

四角螺丝是一种特殊设计的螺丝&#xff0c;其螺纹头部呈四个平行的角状结构&#xff0c;与传统的六角螺丝相比具有独特的外观和功能。这种设计使得四角螺丝在安装和拆卸时更容易使用&#xff0c;并提供了更好的扭矩传递效率。四角螺丝头部呈现四个平行的角&#xff0c;与常见的…

Web前端开发——HTML快速入门

HTML&#xff1a;控制网页的结构CSS&#xff1a;控制网页的表现 一、什么是HTML、CSS &#xff08;1&#xff09;HTML &#xff08;HyperText Markup Languaqe&#xff1a;超文本标记语言&#xff09; 超文本&#xff1a;超越了文本的限制&#xff0c;比普通文本更强大。除了…

上海计算机考研炸了,这所学校慎报!上海大学计算机考研考情分析!

上海大学&#xff08;Shanghai University&#xff09;&#xff0c;简称“上大”&#xff0c;是上海市属、国家“211工程”重点建设的综合性大学&#xff0c;教育部与上海市人民政府共建高校&#xff0c;国防科技工业局与上海市人民政府共建高校&#xff0c;国家“双一流”世界…

羊大师:羊奶养生,解锁健康之道的新密码

在探寻健康与养生的旅途中&#xff0c;我们总渴望找到那把开启健康之门的钥匙。而今&#xff0c;羊奶以其独特的营养价值和健康益处&#xff0c;正悄然成为那把解锁健康之道的新密码。 羊奶&#xff0c;自古以来便是自然赋予的珍贵礼物。它富含优质蛋白、多种维生素及矿物质&am…

【机器学习】Google开源大模型Gemma2:原理、微调训练及推理部署实战

目录 一、引言 二、模型简介 2.1 Gemma2概述 2.2 Gemma2 模型架构 三、训练与推理 3.1 Gemma2 模型训练 3.1.1 下载基座模型 3.1.2 导入依赖库 3.1.3 量化配置 3.1.4 分词器和模型实例化 3.1.5 引入PEFT进行LORA配置 3.1.6 样本数据清洗与加载 3.1.7 模型训练与保…

ERROR: No matching distribution found for numpy

1.原因&#xff1a; 出现这两行英文是因为原先输入pip install numpy的方式不安全&#xff0c;不被信任所以无法下载。 2.解决方法&#xff1a; 改成以下命令执行&#xff1a; pip install numpy -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun…

部署LVS-DR 群集

1 LVS-DR 集群 LVS-DR &#xff08;Linux Virtual Server Director Server ) 工作模式&#xff0c; 是生产环境中最常用的一种工作模式 1.1&#xff1a;LVS-DR工作原理 LVS-DR 模式&#xff0c; Director Server 作为群集的访问入口&#xff0c; 不作为网关使用&#xff0c;…

Spring Boot 的机场投诉管理平台-计算机毕业设计源码22030

摘要 随着航空运输业的迅速发展&#xff0c;机场的客流量不断增加&#xff0c;旅客对机场服务的质量和效率也提出了更高的要求。为了提高机场的服务质量&#xff0c;及时处理旅客的投诉&#xff0c;建立一个高效、便捷的机场投诉管理平台显得尤为重要。 本项目旨在设计与实现一…

BeanUtils拷贝List数据

工具类&#xff1a; package com.ssdl.baize.pub;import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; import org.springframework.beans.BeanUtils;public class BeanConvertUti…

firewalld(8) policies

简介 前面的文章中我们介绍了firewalld的一些基本配置以及NAT的相关配置。在前面的配置中&#xff0c;我们所有的策略都是与zone相关的&#xff0c;例如配置的rich rule&#xff0c;--direct,以及NAT,并且这些配置都是数据包进入zone或者从zone发出时设置的策略。 我们在介绍…

理解神经网络的通道数

理解神经网络的通道数 1. 神经网络的通道数2. 输出的宽度和长度3. 理解神经网络的通道数3.1 都是错误的图片惹的祸3.1.1 没错但是看不懂的图3.1.2 开玩笑的错图3.1.3 给人误解的图 3.2 我或许理解对的通道数3.2.1 动图演示 1. 神经网络的通道数 半路出嫁到算法岗&#xff0c;额…

一分钟教你设置代理服务器的IP地址

许多人购买完代理IP却不会使用&#xff0c;我们来学习一下如何手把手地设置代理服务器的IP地址。无论是为了访问受限网站还是保护隐私&#xff0c;设置代理IP都是一个非常实用的技能。让我们一起来看看怎么做吧&#xff01; 设置代理服务器的IP地址步骤 1. 选择代理服务提供商…

中国IDC圈探访北京•光子1号金融算力中心

今天&#xff0c;“AI”、“大模型”是最炙手可热的话题&#xff0c;全球有海量人群在工作生活中使用大模型&#xff0c;大模型产品涉及多模态&#xff0c;应用范围已涵盖电商、传媒、金融、短视频、制造等众多行业。 而回看2003年的互联网记忆&#xff0c; “上网”“在线”是…

数据库设计规范(DOC文件)

1 编写目的 2 数据库策略 2.1 数据库对象长度策略 2.2 数据完整性策略 2.3 规范化设计与性能之间的权衡策略 2.4 字段类型的定义与使用策略 3 命名规范 3.1 数据库命名规则 3.2 数据库对象命名的一般原则 3.3 表空间(Tablespace)命名规则 3.4 表(Table)命名规则 3.5…