uniapp-含有后端的登录注册页面编写
创建数据库
数据库结构
表名:user
列名数据类型描述idint自增IDusernamevarchar用户名passwordvarchar密码nicknamevarchar昵称
这个方案只保留了id、username、password和nickname四个字段,以最简单的方式存储用户基本信息。需要注意的是,密码应该进行安全处理(如加密),避免泄露敏感信息。如果后续有新增信息需求,则可以随时更改表结构,添加相应的列即可。
数据库代码
-- 创建 usertable 数据库CREATEDATABASEIFNOTEXISTS usertable;-- 切换至 usertable 数据库USE usertable;-- 创建 user 表CREATETABLEIFNOTEXISTSuser(
id INT(11)NOTNULLAUTO_INCREMENT,
username VARCHAR(100)NOTNULLUNIQUE,
password VARCHAR(100)NOTNULL,
nickname VARCHAR(100)NOTNULL,PRIMARYKEY(id))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;-- 添加一些测试数据INSERTINTOuser(username, password, nickname)VALUES('user1','password1','张三');INSERTINTOuser(username, password, nickname)VALUES('user2','password2','李四');INSERTINTOuser(username, password, nickname)VALUES('user3','password3','王五');
这段SQL代码用于创建一个名为
user
的表格,并且添加了一些简单的测试数据。其中,
id
列使用了自增主键约束,保证数据的唯一性。
username
列使用了
unique
约束,确保用户名的唯一性。请注意,
utf8mb4
是一种更高效和更通用的字符编码,支持更广泛的Unicode字符集,所以它比utf-8更推荐使用。
后端编写
创建项目(准备工作)
pom.xml
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="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>userTable</artifactId><version>0.0.1-SNAPSHOT</version><name>userTable</name><description>userTable</description><properties><java.version>1.8</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>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.8.0</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></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/usertable?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
importcom.baomidou.mybatisplus.annotation.TableName;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;@Data@AllArgsConstructor@NoArgsConstructor@TableName("user")// 声明对应的数据库表名(user)publicclassUser{privateLong id;privateString username;privateString password;privateString nickname;}
Result
importlombok.AllArgsConstructor;importlombok.Builder;importlombok.Data;importlombok.NoArgsConstructor;@Data@Builder@AllArgsConstructor@NoArgsConstructorpublicclassResult{privateInteger code;// 状态码privateString message;// 状态信息privateObject data;// 数据}
config
CorsConfig
importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.CorsRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;@ConfigurationpublicclassCorsConfig{@BeanpublicWebMvcConfigurercorsConfigurer(){returnnewWebMvcConfigurerAdapter(){@OverridepublicvoidaddCorsMappings(CorsRegistry registry){// 允许来自本地的8080端口发起的跨域请求
registry.addMapping("/api/**").allowedOrigins("*").allowedMethods("GET","POST","PUT","DELETE").allowCredentials(true).maxAge(3600);}};}}
Mapper
UserMapper
importcom.baomidou.mybatisplus.core.mapper.BaseMapper;importcom.example.usertable.Bean.User;importorg.apache.ibatis.annotations.Mapper;@MapperpublicinterfaceUserMapperextendsBaseMapper<User>{}
Service
UserService
importcom.baomidou.mybatisplus.core.metadata.IPage;importcom.baomidou.mybatisplus.extension.plugins.pagination.Page;importcom.baomidou.mybatisplus.extension.service.IService;importcom.example.usertable.Bean.User;publicinterfaceUserServiceextendsIService<User>{/**
* 分页查询用户列表
*/IPage<User>selectPage(Page<User> page);/**
* 用户注册
*/booleanregister(User user);/**
* 用户登录
*/Userlogin(String username,String password);}
ServiceImpl
UserServiceImpl
importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper;importcom.baomidou.mybatisplus.core.metadata.IPage;importcom.baomidou.mybatisplus.extension.plugins.pagination.Page;importcom.baomidou.mybatisplus.extension.service.impl.ServiceImpl;importcom.example.usertable.Bean.User;importcom.example.usertable.Mapper.UserMapper;importcom.example.usertable.Service.UserService;importlombok.AllArgsConstructor;importorg.springframework.stereotype.Service;importorg.springframework.util.StringUtils;@Service@AllArgsConstructorpublicclassUserServiceImplextendsServiceImpl<UserMapper,User>implementsUserService{@OverridepublicIPage<User>selectPage(Page<User> page){return baseMapper.selectPage(page,null);}/**
* 注册新用户(需先检查用户名是否已被使用)
*/@Overridepublicbooleanregister(User user){String username = user.getUsername();// 根据用户名查询用户User u =this.getOne(newQueryWrapper<User>().eq("username", username));if(u !=null){// 用户名已存在returnfalse;}else{// 将用户保存到数据库returnthis.save(user);}}/**
* 用户登录(根据用户名和密码查询用户)
*/@OverridepublicUserlogin(String username,String password){if(StringUtils.isEmpty(username)||StringUtils.isEmpty(password)){// 用户名和密码不能为空returnnull;}returnthis.getOne(newQueryWrapper<User>().eq("username", username).eq("password", password));}}
Controller
UserController
importcom.baomidou.mybatisplus.core.metadata.IPage;importcom.baomidou.mybatisplus.extension.plugins.pagination.Page;importcom.example.usertable.Bean.Result;importcom.example.usertable.Bean.User;importcom.example.usertable.Service.UserService;importlombok.AllArgsConstructor;importorg.springframework.validation.annotation.Validated;importorg.springframework.web.bind.annotation.*;@AllArgsConstructor@RestController@RequestMapping("/users")publicclassUserController{privatefinalUserService userService;/**
* 获取用户列表(分页)
*/@GetMapping("/")publicResultlist(@RequestParam(defaultValue ="1")Integer pageNum,@RequestParam(defaultValue ="10")Integer pageSize){// 构建分页对象Page<User> page =newPage<>(pageNum, pageSize);// 分页查询用户数据IPage<User> userPage = userService.page(page,null);returnResult.builder().code(200).message("获取成功").data(userPage).build();}/**
* 根据 ID 获取用户信息
*/@GetMapping("/{id}")publicResultdetail(@PathVariableLong id){// 查询用户信息User user = userService.getById(id);if(user !=null){returnResult.builder().code(200).message("获取成功").data(user).build();}else{returnResult.builder().code(404).message("用户不存在").build();}}/**
* 注册
*/@PostMapping("/register")publicResultregister(@RequestBody@ValidatedUser user){boolean success = userService.register(user);if(success){returnResult.builder().code(200).message("注册成功").data(user).build();}else{returnResult.builder().code(500).message("用户名已存在").build();}}/**
* 登录
*/@PostMapping("/login")publicResultlogin(@RequestBodyUser user){String username = user.getUsername();String password = user.getPassword();// 查询用户User loginUser = userService.login(username, password);if(loginUser !=null){returnResult.builder().code(200).message("登录成功").data(loginUser).build();}else{returnResult.builder().code(401).message("用户名或密码错误").build();}}/**
* 新增用户
*/@PostMapping("/")publicResultadd(@RequestBody@ValidatedUser user){boolean success = userService.save(user);if(success){returnResult.builder().code(200).message("新增成功").data(user).build();}else{returnResult.builder().code(500).message("新增失败").data(user).build();}}/**
* 更新用户信息
*/@PutMapping("/{id}")publicResultupdate(@PathVariableLong id,@RequestBody@ValidatedUser user){
user.setId(id);boolean success = userService.updateById(user);if(success){returnResult.builder().code(200).message("更新成功").data(user).build();}else{returnResult.builder().code(500).message("更新失败").data(user).build();}}/**
* 删除用户
*/@DeleteMapping("/{id}")publicResultdelete(@PathVariableLong id){boolean success = userService.removeById(id);if(success){returnResult.builder().code(200).message("删除成功").build();}else{returnResult.builder().code(500).message("删除失败").build();}}}
Postman测试
测试所有的接口
以下是基于8081端口号的 Postman 测试:
1. 获取用户列表(分页)
请求地址:
http://localhost:8081/users/
请求方法:GET
请求参数:
参数名称参数类型是否必须默认值参数说明pageNumInteger否1当前页码pageSizeInteger否10每页记录数
成功响应:
{"code":200,"message":"获取成功","data":{"records":[{"id":1,"username":"user1","password":"password1","nickname":"张三"},{"id":2,"username":"user2","password":"password2","nickname":"李四"},{"id":3,"username":"user3","password":"password3","nickname":"王五"}],"total":0,"size":10,"current":1,"orders":[],"optimizeCountSql":true,"hitCount":false,"countId":null,"maxLimit":null,"searchCount":true,"pages":0}}
2. 根据 ID 获取用户信息
请求地址:
http://localhost:8081/users/{id}
请求方法:GET
请求路径参数:
参数名称参数类型是否必须示例值参数说明idLong是1用户 ID
成功响应:
{"code":200,"message":"获取成功","data":{"id":1,"username":"user1","password":"password1","nickname":"张三"}}
3. 注册
请求地址:
http://localhost:8081/users/register
请求方法:POST
请求参数:
参数名称参数类型是否必须示例值参数说明usernameString是user-11用户名passwordString是pass-11密码nicknameString否lihua昵名
请求示例:
{"username":"user-11","password":"pass-11","nickname":"lihua"}
成功响应:
{"code":200,"message":"注册成功","data":{"id":4,"username":"user-11","password":"pass-11","nickname":"lihua"}}
失败响应:
{"code":500,"message":"用户名已存在"}
4. 登录
请求地址:
http://localhost:8081/users/login
请求方法:POST
请求参数:
参数名称参数类型是否必须示例值参数说明usernameString是user-1用户名passwordString是pass-1密码
请求示例:
{"username":"user2","password":"password2"}
成功响应:
{"code":200,"message":"登录成功","data":{"password":"password2","nickname":"李四","id":2,"username":"user2"}}
失败响应:
{"code":401,"message":"用户名或密码错误","data":null}
5. 新增用户
请求地址:
http://localhost:8081/users/
请求方法:POST
请求参数:
参数名称参数类型是否必须示例值参数说明usernameString是user-12用户名passwordString是pass-12密码nicknameString否小李昵名
请求示例:
{"username":"user-12","password":"pass-12","nickname":"小李"}
成功响应:
{"code":200,"message":"新增成功","data":{"id":5,"username":"user-12","password":"pass-12","nickname":"小李"}}
失败响应:
{"code":500,"message":"新增失败"}
6. 更新用户信息
请求地址:
http://localhost:8081/users/{id}
请求方法:PUT
请求路径参数:
参数名称参数类型是否必须示例值参数说明usernameString否user-12-update用户名passwordString否pass-12-update密码emailString否user-12-update@example.com邮箱phoneString否12345678901手机号
请求示例:
{"username":"user-13","password":"pass-13","nickname":"小李"}
成功响应:
{"code":200,"message":"更新成功","data":{"id":1,"username":"user-13","password":"pass-13","nickname":"小李"}}
失败响应:
{"code":500,"message":"更新失败"}
7. 删除用户
请求地址:
http://localhost:8081/users/{id}
请求方法:DELETE
请求路径参数:
参数名称参数类型是否必须示例值参数说明idLong是12用户 ID
成功响应:
{"code":200,"message":"删除成功"}
失败响应:
{"code":500,"message":"删除失败"}
前端编写
页面编写
效果展示
文件目录
pages.json
manifest.json
{"name":"LoginAndRegister","appid":"","description":"","versionName":"1.0.0","versionCode":"100","transformPx":false,/* 5+App特有相关 */"app-plus":{"usingComponents":true,"nvueStyleCompiler":"uni-app","compilerVersion":3,"splashscreen":{"alwaysShowBeforeRender":true,"waiting":true,"autoclose":true,"delay":0},/* 模块配置 */"modules":{},/* 应用发布信息 */"distribute":{/* android打包配置 */"android":{"permissions":["<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>","<uses-permission android:name=\"android.permission.VIBRATE\"/>","<uses-permission android:name=\"android.permission.READ_LOGS\"/>","<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>","<uses-feature android:name=\"android.hardware.camera.autofocus\"/>","<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.CAMERA\"/>","<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>","<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>","<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>","<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>","<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>","<uses-feature android:name=\"android.hardware.camera\"/>","<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"]},/* ios打包配置 */"ios":{},/* SDK配置 */"sdkConfigs":{}}},/* 快应用特有相关 */"quickapp":{},/* 小程序特有相关 */"mp-weixin":{"appid":"","setting":{"urlCheck":false},"usingComponents":true},"mp-alipay":{"usingComponents":true},"mp-baidu":{"usingComponents":true},"mp-toutiao":{"usingComponents":true},"uniStatistics":{"enable":false},"vueVersion":"2","h5":{"devServer":{"port":8080,//浏览器运行端口"disableHostCheck":true,//设置跳过host检查"proxy":{"/api":{"target":"http://localhost:8081",//目标接口域名"changeOrigin":true,//是否跨域"secure":false,// 设置支持https协议的代理"pathRewrite":{"^/api":""}}}}}}
index.vue
<template><viewclass="content"><imageclass="logo"src="/static/logo.png"></image><viewclass="text-area"><textclass="title">{{title}}</text><button@click="handleClick">点击我</button></view></view></template><script>exportdefault{data(){return{title:'Hello'}},onLoad(){},methods:{handleClick(){
console.log('您点击了该按钮!')}}}</script><style>.content{display: flex;flex-direction: column;align-items: center;justify-content: center;}.logo{height: 200rpx;width: 200rpx;margin-top: 200rpx;margin-left: auto;margin-right: auto;margin-bottom: 50rpx;}.text-area{display: flex;justify-content: center;}.title{font-size: 36rpx;color: #8f8f94;}</style>
login.vue
<template><viewclass="login"><imageclass="logo"src="/static/logo.png"></image><viewclass="input-item"><inputtype="text"v-model="username"placeholder="请输入用户名"></view><viewclass="input-item"><inputtype="password"v-model="password"placeholder="请输入密码"></view><button@click="login"class="login-btn">登录</button><button@click="goToRegister"class="register-btn">注册</button></view></template><script>import axios from'axios'exportdefault{data(){return{username:'',password:''}},methods:{login(){if(!this.username ||!this.password){
uni.showToast({title:'请填写用户名和密码',icon:'none'})return}// 发送请求验证用户
axios.post('/api/users/login',{username:this.username,password:this.password
}).then(res=>{
console.log(res.data.code)if(res.data.code ===200){// 将用户信息保存到客户端本地缓存中
uni.setStorageSync('userInfo',{id: res.data.data.id,username: res.data.data.username,password: res.data.data.password,nickname: res.data.data.nickname
})// 跳转到首页
uni.navigateTo({url:'/pages/index/index'})}else{
uni.showToast({title: res.data.message,icon:'none'})}}).catch(err=>{
uni.showToast({title:'网络请求失败,请重试',icon:'none'})})},goToRegister(){
uni.navigateTo({url:'/pages/register/register'})}}}</script><stylescoped>.login{display: flex;flex-direction: column;justify-content: center;align-items: center;margin-top: 100rpx;}.logo{width: 200rpx;height: 200rpx;margin-bottom: 20rpx;}.login-form{width: 90%;padding: 40rpx;background-color: #fff;border-radius: 5rpx;}.input-item{width: 80%;margin: 10rpx 0;border-bottom: 1rpx solid #ddd;}input{width: 100%;height: 50rpx;padding: 10rpx;font-size: 16rpx;outline: none;border: none;}.login-btn{display: block;margin: 30rpx auto 0;width: 80%;height: 80rpx;line-height: 80rpx;text-align: center;background-color: #007aff;color: #fff;border-radius: 5rpx;font-size: 20rpx;}.register-btn{margin-top: 20rpx;color: #007aff;width: 60%;height: 80rpx;}</style>
register.vue
<template><viewclass="register"><imageclass="logo"src="/static/logo.png"></image><formclass="register-form"><viewclass="input-item"><inputtype="text"v-model="nickname"placeholder="请输入昵称"></view><viewclass="input-item"><inputtype="text"v-model="username"placeholder="请输入用户名"></view><viewclass="input-item"><inputtype="password"v-model="password"placeholder="请输入密码"></view><viewclass="input-item"><inputtype="password"v-model="confirmPassword"placeholder="请确认密码"></view><buttontype="button"class="register-btn"@click="register">注册</button></form><buttonclass="back-btn"@click="goBack">返回</button></view></template><script>import axios from'axios';exportdefault{data(){return{username:'',password:'',confirmPassword:'',nickname:''};},methods:{asyncregister(){if(!this.username ||!this.password ||!this.nickname){
uni.showToast({title:'请填写完整信息',icon:'none'});return;}if(this.password !==this.confirmPassword){
uni.showToast({title:'两次输入密码不一致',icon:'none'});return;}try{const response =await axios.post('/api/users/register',{username:this.username,password:this.password,nickname:this.nickname
});const responseData = response.data;if(responseData.code ===200){
uni.showToast({title: responseData.message,icon:'success'});
uni.navigateTo({url:'/pages/login/login'});}else{
uni.showToast({title: responseData.message,icon:'none'});}}catch(error){let errorMessage ='注册失败,请稍后再试';if(error.response){if(error.response.status ===500){
errorMessage = error.response.data.message;}}
uni.showToast({title: errorMessage,icon:'none'});}},goBack(){
uni.navigateBack();}}};</script><stylescoped>.register{display: flex;flex-direction: column;justify-content: center;align-items: center;margin-top: 100rpx;}.logo{width: 200rpx;height: 200rpx;margin-bottom: 20rpx;}.register-form{width: 90%;padding: 40rpx;background-color: #fff;border-radius: 5rpx;}.input-item{margin: 10rpx 0;border-bottom: 1rpx solid #ddd;}input{width: 100%;height: 50rpx;padding: 10rpx;font-size: 16rpx;outline: none;border: none;}.register-btn{display: block;margin: 30rpx auto 0;width: 90%;height: 80rpx;line-height: 80rpx;text-align: center;background-color: #007aff;color: #fff;border-radius: 5rpx;font-size: 20rpx;}.back-btn{margin-top: 20rpx;color: #007aff;width: 60%;height: 80rpx;}</style>
版权归原作者 极客李华 所有, 如有侵权,请联系我们删除。