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

简介: 基于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 工具进行接口测试

相关文章
|
开发者 容器
44.[HarmonyOS NEXT RelativeContainer案例一] 掌握组件锚点布局:打造灵活精准的UI定位系统
在HarmonyOS NEXT的UI开发中,精确控制组件位置是构建复杂界面的关键。RelativeContainer作为一种强大的布局容器,通过锚点系统提供了精确定位能力,使开发者能够创建出灵活且精准的UI布局。本教程将详细讲解如何使用RelativeContainer的锚点布局功能,帮助你掌握这一核心技术。
436 4
|
设计模式 缓存 容器
06.HarmonyOS Next UI进阶:Text组件与视觉样式完全指南
在HarmonyOS Next应用开发中,Text组件是最基础也是最常用的UI元素之一。它不仅用于显示文本内容,还可以通过丰富的样式属性实现各种视觉效果。掌握Text组件的样式设置,是构建精美UI界面的基础技能。
621 1
|
前端开发 安全 开发工具
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
1202 90
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
JSON 自然语言处理 前端开发
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
831 72
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
|
Linux Go iOS开发
IDA 9.2 发布:Golang 改进、新 UI 组件、类型解析等
IDA Pro 9.2 (macOS, Linux, Windows) - 强大的反汇编程序、反编译器和多功能调试器
1733 0
|
Web App开发 前端开发 JavaScript
Element UI框架中自定义input组件的placeholder样式。
确保这些样式在你的应用程序CSS文件中定义,且该文件已正确加载到项目中。通过以上方法,可以控制Element UI组件中input的placeholder样式,使其满足特定的设计要求。这些更改都是基于CSS伪元素进行的,因此并不会对DOM结构产生改变,保持了原有结构的简洁和高效。
981 12
|
移动开发 开发者
仓颉开发语言入门教程:常见UI组件介绍和一些问题踩坑
仓颉开发语言即将发布一周年,虽已有知名App应用,但教程稀缺且官网文档不够完善。幽蓝君推出系列教程,从零开始系统讲解移动开发。本期介绍常用UI组件:按钮、文本、图片、输入框与搜索框的使用方法及注意事项,帮助开发者快速上手仓颉语言。
「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件
本篇将带你实现一个自定义天气预报组件。用户可以通过选择不同城市来获取相应的天气信息,页面会显示当前城市的天气图标、温度及天气描述。这一功能适合用于动态展示天气信息的小型应用。
866 38
「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件
|
JavaScript 数据安全/隐私保护
Vue Amazing UI 组件库(Vue3+TypeScript+Vite 等最新技术栈开发)
Vue Amazing UI 是一个基于 Vue 3、TypeScript、Vite 等最新技术栈开发构建的现代化组件库,包含丰富的 UI 组件和常用工具函数,并且持续不断维护更新中。另外,组件库全量使用 TypeScript,支持自动按需引入和 Tree Shaking 等,能够显著提升开发效率,降低开发成本。
954 5
Vue Amazing UI 组件库(Vue3+TypeScript+Vite 等最新技术栈开发)
|
人工智能 自然语言处理 前端开发
Flame:开源AI设计图转代码模型!生成React组件,精准还原UI+动态交互效果
Flame 是一款开源的多模态 AI 模型,能够将 UI 设计图转换为高质量的现代前端代码,支持 React 等主流框架,具备动态交互、组件化开发等功能,显著提升前端开发效率。
2745 1

热门文章

最新文章