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

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 基于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 工具进行接口测试

相关文章
|
23天前
|
JavaScript 前端开发
如何优雅的只在当前页面中覆盖ui库中组件的样式(vue的问题)
如何优雅的只在当前页面中覆盖ui库中组件的样式(vue的问题)
15 0
如何优雅的只在当前页面中覆盖ui库中组件的样式(vue的问题)
|
1月前
|
搜索推荐 BI 开发者
sap.ui.comp.smarttable.SmartTable 组件 beforeRebindTable 事件的用法
sap.ui.comp.smarttable.SmartTable 组件 beforeRebindTable 事件的用法
22 0
|
2月前
|
缓存 前端开发 Go
从4开始,在后端系统中增加用户注册和登录功能
从4开始,在后端系统中增加用户注册和登录功能
21 0
|
2月前
|
索引
UniApp 组件 u-tabs 详细讲解
UniApp 组件 u-tabs 详细讲解
247 1
|
2月前
|
前端开发 JavaScript
u-popup组件在UniApp中的讲解
u-popup组件在UniApp中的讲解
43 0
|
3月前
|
开发框架 前端开发 .NET
七天.NET 8操作SQLite入门到实战 - (1)第七天BootstrapBlazor UI组件库引入
七天.NET 8操作SQLite入门到实战 - (1)第七天BootstrapBlazor UI组件库引入
|
3月前
uniapp导航栏组件如何使用
uniapp导航栏组件如何使用
36 0
|
3月前
uniapp项目实践第四章:如何安装uni-ui组件库
uniapp项目实践第四章:如何安装uni-ui组件库
103 0
|
1月前
|
开发者 iOS开发
UniApp打包教程:使用HBuilder X和AppUploader完成原生App云打包和上架指南“
UniApp打包教程:使用HBuilder X和AppUploader完成原生App云打包和上架指南“
49 3
|
2月前
|
资源调度 JavaScript
Vue + Element-ui组件上传图片报错问题解决方案
Vue + Element-ui组件上传图片报错问题解决方案

热门文章

最新文章