基于uniapp原生组件uni-ui 做一个登录注册与个人中心(后端篇)

基于uniapp原生组件uni-ui 做一个登录注册与个人中心(后端篇)

简介

本文使用springboot+mybatis-plus实现用户表的后端代码,包含加密功能。

数据库

CREATE TABLE `user`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  `password_hash` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  `salt` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  `grade` int NOT NULL,
  `role` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = DYNAMIC;

在这里插入图片描述

项目编写

  • 创建项目
    在这里插入图片描述

在这里插入图片描述

  • 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 https://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.11</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>UserDemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>UserDemo</name>
    <description>UserDemo</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.7.6</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>2.5.6</version>
    </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.6.3.Final</version>
    </dependency>


    <dependency>
        <groupId>javax.persistence</groupId>
        <artifactId>javax.persistence-api</artifactId>
        <version>2.2</version>
    </dependency>

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.2</version>
    </dependency>



    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-api</artifactId>
        <version>0.11.2</version>
    </dependency>

    <!-- 如果要使用 jjwt 的实现,还需要添加以下依赖 -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-impl</artifactId>
        <version>0.11.2</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-jackson</artifactId>
        <version>0.11.2</version>
        <scope>runtime</scope>
    </dependency>
    <!-- Hibernate Validator -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.8.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.12.0</version>
    </dependency>
</dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

  • application.properties
# ?????
spring.datasource.url=jdbc:mysql://localhost:3306/exam4?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# ???????
server.port=8081    

# MyBatis-Plus ??
mybatis-plus.mapper-locations=classpath:/mapper/*.xml
mybatis-plus.type-aliases-package=com.example.demo.entity
mybatis-plus.global-config.db-config.id-type=auto
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.use-generated-keys=true
mybatis-plus.configuration.map-enum-as-ordinal=false
mybatis-plus.configuration.enum-handler=com.baomidou.mybatisplus.extension.handlers.MybatisEnumTypeHandler

代码编写

项目结构
在这里插入图片描述

Bean

User

import lombok.AllArgsConstructor;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.*;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User {
    
    
    @TableId(type = IdType.AUTO)
    private Long id;
    private String username;
    private String avatar;
    private String passwordHash;
    private String salt;
    private int grade;
    private String role;
}

Result

import lombok.Data;
import org.springframework.lang.Nullable;

@Data
public class Result<T> {
    
    
    private int code;
    private String message;
    @Nullable
    private T data;

    public static <T> Result<T> success(T data) {
    
    
        return success(data, "操作成功");
    }

    public static <T> Result<T> success(T data, String message) {
    
    
        return new Result<>(200, message, data);
    }

    public static <T> Result<T> fail(String message) {
    
    
        return new Result<>(500, message, null);
    }

    public Result(int code, String message, @Nullable T data) {
    
    
        this.code = code;
        this.message = message;
        this.data = data;
    }
}

Tool

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 安全相关工具类
 * 提供各种安全相关的操作方法
 */
public class SecurityTool {
    
    

    /**
     * 对字符串进行MD5加密
     * @param str 待加密的字符串
     * @return 加密结果
     */
    public static String MD5Encode(String str) {
    
    
        try {
    
    
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(str.getBytes());   //对字符串加密
            byte[] encodedBytes = md.digest();
            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < encodedBytes.length; i++) {
    
    
                String hex = Integer.toHexString(0xff & encodedBytes[i]);
                if (hex.length() == 1) {
    
    
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
    
    
           //省略异常处理
        }
        return null;
    }

}

Config

CorsConfig

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class CorsConfig {
    
    
    @Bean
    public WebMvcConfigurer corsConfigurer() {
    
    
        return new WebMvcConfigurerAdapter() {
    
    
            @Override
            public void addCorsMappings(CorsRegistry registry) {
    
    
                // 允许来自本地的8080端口发起的跨域请求
                registry.addMapping("/api/**")
                    .allowedOrigins("*")
                    .allowedMethods("GET", "POST", "PUT", "DELETE")
                    .allowCredentials(true).maxAge(3600);
            }
        };
    }
}

Mapper

UserMapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.userdemo.Bean.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
    
    

}

Service

IUserService

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.userdemo.Bean.User;

public interface IUserService extends IService<User> {
    
    
    /**
     * 用户注册
     * @param user 待注册用户信息
     * @return 注册成功返回true,失败返回false
     */
    boolean register(User user);

    /**
     * 用户登录
     * @param username 用户名
     * @param password 密码
     * @return 登录成功返回对应用户的信息,失败返回null
     */
    User login(String username, String password);

    /**
     * 根据用户名获取用户
     * @param username 用户名
     * @return 用户
     */
    User getByUsername(String username);
}

Impl

UserServiceImpl

import java.util.ArrayList;
import java.util.Random;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    
    

    /**
     * 用户注册实现
     * 先查用户名是否存在,不存在则加密密码进行保存
     * @param user 待注册用户信息
     * @return 注册成功返回true,失败返回false
     */
    @Override
    public boolean register(User user) {
    
    
        String username = user.getUsername();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);   //查询用户名是否存在
        User hasUser = getOne(wrapper);
        if (hasUser != null) {
    
      //数据库中已经存在该用户名,注册失败
            return false;
        }
        // 随机生成一个头像
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("https://pic3.zhimg.com/v2-d6ddf0128212235dddf76df7f4383f53.jpg");
        arrayList.add("https://p0.ssl.img.360kuai.com/t01948ff2341a5d1ac3.jpg");
        arrayList.add("https://pic3.zhimg.com/v2-65020b1231ba55d55ee3d6a29ff3df26_r.jpg");
        arrayList.add("https://pic2.zhimg.com/v2-fc348d5e926116782149d2151dc09834.jpg");
        arrayList.add("https://pic4.zhimg.com/v2-797973e16edcd0ccaab44cfbfa08d2d3_r.jpg");
        Random random = new Random();
        user.setAvatar(arrayList.get(random.nextInt(arrayList.size())));

        String password = user.getPasswordHash();
        String salt = RandomStringUtils.randomAlphabetic(6);    //生成盐
        String encryptedPwd = SecurityTool.MD5Encode(password + salt);   //对密码+盐进行加密
        user.setPasswordHash(encryptedPwd);
        user.setSalt(salt);
        boolean successFlag = save(user);
        return successFlag;
    }

    @Override
    public User getByUsername(String username) {
    
    
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        return getOne(queryWrapper);
    }

    /**
     * 用户登录实现
     * 先使用用户名查询对应用户,然后进行密码比对
     * @param username 用户名
     * @param password 密码
     * @return 如果成功则返回对应用户信息(不包含密码和盐),失败返回null
     */
    @Override
    public User login(String username, String password) {
    
    
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username); //根据用户名找到对应的User对象
        User user = getOne(wrapper);
        if (user == null) {
    
      //未找到该用户
            return null;
        }
        String salt = user.getSalt();
        String encryptedPwd = SecurityTool.MD5Encode(password + salt);  //对密码+盐进行加密
        if (!encryptedPwd.equals(user.getPasswordHash())) {
    
      //密码错误
            return null;
        }
        user.setPasswordHash(null); //不暴露密码hash与盐值Salt给前端
        user.setSalt(null);
        return user; //一切正常,返回相应用户信息
    }
}

Controller

UserController

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.example.userdemo.Bean.Result;
import com.example.userdemo.Bean.User;
import com.example.userdemo.Service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@RestController
@RequestMapping("/user")
public class UserController {
    
    

    @Autowired
    private IUserService userService;

    /**
     * 获取全部用户信息列表
     */
    @GetMapping("/all")
    public Result<List<User>> listAllUsers() {
    
    
        List<User> userList = userService.list();
        return Result.success(userList);
    }

    /**
     * 根据用户ID获取用户信息
     */
    @GetMapping("/{id}")
    public Result<User> getUserById(@PathVariable(value = "id") Long id) {
    
    
        User user = userService.getById(id);
        if (user == null) {
    
    
            return Result.fail("该用户不存在");
        }
        return Result.success(user);
    }

    /**
     * 更新用户信息
     */
    @PostMapping("/save")
    public Result<Boolean> UpdateUser(@RequestBody User user) {
    
    
        // 判断新的username是否合法
        if (StringUtils.isBlank(user.getUsername())) {
    
    
            return Result.fail("更新失败:用户名不能为空");
        }

        // 校验用户名是否重复,如果已经存在就返回错误信息
        User existingUser = userService.getByUsername(user.getUsername());
        if (existingUser != null && !existingUser.getId().equals(user.getId())) {
    
    
            return Result.fail("更新失败:该用户名已被占用");
        }

        // 获取旧用户并更新部分信息
        User oldUser = userService.getById(user.getId());
        if (oldUser == null) {
    
    
            return Result.fail("更新失败:该用户不存在");
        }
        oldUser.setUsername(user.getUsername());
        oldUser.setGrade(user.getGrade());
        oldUser.setPasswordHash(user.getPasswordHash());

        boolean flag = userService.save(oldUser);
        if (flag) {
    
    
            return Result.success(true, "保存成功");
        } else {
    
    
            return Result.fail("保存失败");
        }
    }




    /**
     * 根据用户ID删除用户信息
     */
    @DeleteMapping("/delete/{id}")
    public Result<Boolean> deleteUserById(@PathVariable(value = "id") Long id) {
    
    
        boolean flag = userService.removeById(id);
        if (flag) {
    
    
            return Result.success(true, "删除成功");
        } else {
    
    
            return Result.fail("删除失败");
        }
    }

    /**
     * 用户注册
     */
    @PostMapping("/register")
    public Result<Boolean> register(@RequestBody User user) {
    
    
        System.out.println(user);
        boolean flag = userService.register(user);
        if (flag) {
    
    
            return Result.success(true, "注册成功");
        } else {
    
    
            return Result.fail("注册失败,用户名已被占用");
        }
    }

    /**
     * 用户登录
     */
    @PostMapping("/login")
    public Result<User> login(@RequestBody User user) {
    
    
        String username = user.getUsername();
        String password = user.getPasswordHash();
        User user2 = userService.login(username, password);
        if (user == null) {
    
    
            return Result.fail("用户名或密码错误,登录失败");
        } else {
    
    
            return Result.success(user2, "登录成功");
        }
    }
}

Postman测试

好的,请按照以下步骤在 Postman 中测试接口:

  1. 以 POST 请求方式发送以下数据至 http://localhost:8081/user/register
{
    
    
    "username": "test123",
    "passwordHash": "test1234",
    "grade": 1
}

若注册成功,会返回请求成功信息:

{
    
    
    "code": 200,
    "message": "注册成功",
    "data": true
}

若注册失败(用户名已存在),会返回出错信息:

{
    
    
    "code": 500,
    "message": "注册失败,用户名已被占用",
    "data": null
}
  1. 以 POST 请求方式发送以下数据至 http://localhost:8080/user/login
{
    
    
    "username": "test123",
    "password": "test1234"
}

若登录成功,会返回用户信息:

{
    
    
    "code": 200,
    "message": "登录成功",
    "data": {
    
    
        "id": 用户ID,
        "username": "test123",
        "avatar": null,
        "passwordHash": null,
        "salt": null,
        "grade": 1,
        "role": null
    }
}

若登录失败(用户名或密码错误),会返回出错信息:

{
    
    
    "code": 500,
    "message": "用户名或密码错误,登录失败",
    "data": null
}
  1. 以 GET 请求方式发送以下数据至 http://localhost:8080/user/all

若查询全部用户信息列表成功,会返回用户信息列表:

{
    
    
    "code": 200,
    "message": "操作成功",
    "data": [
        {
    
    
            "id": 用户1ID,
            "username": "test123",
            "avatar": null,
            "passwordHash": null,
            "salt": null,
            "grade": 0,
            "role": null
        },
        {
    
    
            "id": 用户2ID,
            "username": "user",
            "avatar": null,
            "passwordHash": null,
            "salt": null,
            "grade": 1,
            "role": null
        }
    ]
}
  1. 以 GET 请求方式发送以下数据至 http://localhost:8080/user/1 (用户ID为 1 的具体用户):

若根据 ID 获取用户信息成功,会返回对应的用户信息:

{
    
    
    "code": 200,
    "message": "操作成功",
    "data": {
    
    
        "id": 用户1ID,
        "username": "test123",
        "avatar": null,
        "passwordHash": null,
        "salt": null,
        "grade": 0,
        "role": null
    }
}

若未找到该用户,会返回出错信息:

{
    
    
    "code": 500,
    "message": "该用户不存在",
    "data": null
}
  1. 以 POST 请求方式发送以下数据至 http://localhost:8080/user/save
{
    
    
    "id": <当前用户ID>,
    "username": "test321",
    "passwordHash": "test4321",
    "grade": 2
}

若新增或更新成功,会返回请求成功信息:

{
    
    
    "code": 200,
    "message": "保存成功",
    "data": true
}

注意:若采用 POST 请求方式,请在请求头中添加 Content-Type 为 application/json。

希望这个例子可以帮助您更好地理解如何使用 Spring Boot 框架和 Postman 工具进行接口测试。

猜你喜欢

转载自blog.csdn.net/qq_51447496/article/details/130976239