• vue+springboot实验个人信息,修改密码,忘记密码功能实现


    前端部分

    新增Person(个人页面),Password(修改密码页面),还需要对Manager,login页面进行修改

    router文件夹下的index.js:

     

    1. import Vue from 'vue'
    2. import VueRouter from 'vue-router'
    3. import Manager from '../views/Manager.vue'
    4. // 解决导航栏或者底部导航tabBar中的vue-router在3.0版本以上频繁点击菜单报错的问题。
    5. const originalPush = VueRouter.prototype.push
    6. VueRouter.prototype.push = function push (location) {
    7. return originalPush.call(this, location).catch(err => err)
    8. }
    9. Vue.use(VueRouter)
    10. const routes = [
    11. {
    12. path: '/',
    13. name: 'manager',
    14. component: Manager,
    15. children:[
    16. {path:'home',name:'Home',meta:{ name:'系统首页' },component:()=>import('../views/manager/Home.vue')},
    17. {
    18. path:'user',name:'User',meta:{ name:'用户信息' },component:()=>import('../views/manager/User.vue')
    19. },
    20. {
    21. path:'403',name:'Auth',meta:{ name:'无权限' },component:()=>import('../views/Auth.vue')
    22. },
    23. {
    24. path:'Person',name:'person',meta:{ name:'个人信息' },component:()=>import('../views/manager/Person.vue')
    25. },
    26. {
    27. path:'Password',name:'password',meta:{ name:'修改密码' },component:()=>import('../views/manager/Password.vue')
    28. }
    29. ],
    30. redirect:'/home'
    31. },
    32. {
    33. path: '/about',
    34. name: 'about',
    35. // route level code-splitting
    36. // this generates a separate chunk (about.[hash].js) for this route
    37. // which is lazy-loaded when the route is visited.
    38. component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
    39. },
    40. {
    41. path:'/login',
    42. name:'login',
    43. meta:{ name:'登录' },
    44. component: ()=>import('../views/login.vue')
    45. },
    46. {
    47. path:'/register',
    48. name:'register',
    49. meta:{ name:'注册' },
    50. component: ()=>import('../views/register.vue')
    51. },
    52. {
    53. path:'*',
    54. name:'404',
    55. meta:{ name:'无法访问' },
    56. component: ()=>import('../views/404.vue')
    57. }
    58. ]
    59. const router = new VueRouter({
    60. mode: 'history',
    61. base: process.env.BASE_URL,
    62. routes
    63. })
    64. router.beforeEach((to,from,next)=>{
    65. let adminPaths=['/user']
    66. let user=JSON.parse(localStorage.getItem('honey-user')||'{}')
    67. if(user.role !== '管理员' && adminPaths.includes(to.path)){
    68. next('/403')
    69. }else{
    70. next()
    71. }
    72. })
    73. export default router

    Person.vue

    1. <template>
    2. <div>
    3. <el-card style="width: 50%">
    4. <el-form :model="user" label-width="80px" style="padding-right: 20px">
    5. <div style="margin: 15px;text-align: center">
    6. <el-upload
    7. class="avatar-uploader"
    8. action="http://localhost:9090/file/upload"
    9. :headers="{ token: user.token }"
    10. :show-file-list="false"
    11. :on-success="handleAvatarSuccess">
    12. <img v-if="user.avatar" :src="user.avatar" class="avatar">
    13. <i v-else class="el-icon-plus avatar-uploader-icon"></i>
    14. </el-upload>
    15. </div>
    16. <el-form-item label="用户名" prop="username">
    17. <el-input v-model="user.username" disabled></el-input>
    18. </el-form-item>
    19. <el-form-item label="姓名" prop="name">
    20. <el-input v-model="user.name"></el-input>
    21. </el-form-item>
    22. <el-form-item label="电话" prop="phone">
    23. <el-input v-model="user.phone"></el-input>
    24. </el-form-item>
    25. <el-form-item label="邮箱" prop="email">
    26. <el-input v-model="user.email"></el-input>
    27. </el-form-item>
    28. <el-form-item label="地址" prop="address">
    29. <el-input type="textarea" v-model="user.address"></el-input>
    30. </el-form-item>
    31. </el-form>
    32. <div style="text-align: center;margin-bottom: 20px"><el-button type="primary" @click="update">保存</el-button></div>
    33. </el-card>
    34. </div>
    35. </template>
    36. <script>
    37. export default {
    38. data(){
    39. return{
    40. user:JSON.parse(localStorage.getItem('honey-user'||'{}'))
    41. }
    42. },
    43. methods:{
    44. update(){
    45. this.$request.put('/user/update',this.user).then(res=>{
    46. if(res.code==='200'){
    47. this.$message.success('保存成功')
    48. localStorage.setItem('honey-user',JSON.stringify(this.user))
    49. this.$emit('update:user',this.user)
    50. }else{
    51. this.$message.error(res.msg)
    52. }
    53. })
    54. },
    55. handleAvatarSuccess(response,file,fileList){
    56. console.log(response)
    57. this.user.avatar=response.data
    58. }
    59. }
    60. }
    61. </script>
    62. <style scoped>
    63. /deep/.el-form-item__label{
    64. font-weight: bold;
    65. }
    66. /deep/.el-upload{
    67. border-radius: 50%;
    68. }
    69. /deep/.avatar-uploader .el-upload {
    70. border: 1px dashed #d9d9d9;
    71. cursor: pointer;
    72. position: relative;
    73. overflow: hidden;
    74. border-radius: 50%;
    75. }
    76. /deep/.avatar-uploader .el-upload:hover {
    77. border-color: #409EFF;
    78. }
    79. .avatar-uploader-icon {
    80. font-size: 28px;
    81. color: #8c939d;
    82. width: 178px;
    83. height: 178px;
    84. line-height: 178px;
    85. text-align: center;
    86. border-radius: 50%;
    87. }
    88. .avatar {
    89. width: 178px;
    90. height: 178px;
    91. display: block;
    92. border-radius: 50%;
    93. }
    94. </style>

    Password.vue:

    1. <template>
    2. <div>
    3. <el-card style="width: 50%">
    4. <el-form ref="fromRef" :model="user" label-width="80px" style="padding-right: 20px" :rules="rules">
    5. <el-form-item label="原始密码" prop="password">
    6. <el-input v-model="user.password" show-password></el-input>
    7. </el-form-item>
    8. <el-form-item label="新密码" prop="newPassword">
    9. <el-input v-model="user.newPassword"></el-input>
    10. </el-form-item>
    11. <el-form-item label="确认密码" prop="confirmPassword">
    12. <el-input v-model="user.confirmPassword"></el-input>
    13. </el-form-item>
    14. <div style="text-align: center;margin-bottom: 20px"><el-button type="primary" @click="update">确认修改</el-button></div>
    15. </el-form>
    16. </el-card>
    17. </div>
    18. </template>
    19. <script>
    20. export default {
    21. data(){
    22. const validatePassword = (rule, value, callback) => {
    23. if (value === '') {
    24. callback(new Error('请输入确认密码'));
    25. } else if(value !== this.user.newPassword){
    26. callback(new Error('两次密码不一致'));
    27. } else {
    28. callback();
    29. }
    30. };
    31. return{
    32. user:JSON.parse(localStorage.getItem('honey-user'||'{}')),
    33. rules:{
    34. password:[{
    35. required:true,
    36. message:'请输入原始密码',
    37. trigger:'blur'
    38. }],
    39. newPassword:[{
    40. required:true,
    41. message:'请输入新密码',
    42. trigger:'blur'
    43. }],
    44. confirmPassword:[{
    45. validator:validatePassword,
    46. required:true,
    47. trigger:'blur',
    48. }]
    49. }
    50. }
    51. },
    52. methods:{
    53. update(){
    54. this.$refs.fromRef.validate((valid)=>{
    55. if(valid){
    56. this.user.password=this.user.newPassword
    57. this.$request.put('/user/update',this.user).then(res=>{
    58. if(res.code==='200'){
    59. this.$message.success('保存成功')
    60. this.$router.push('/login')
    61. }else{
    62. this.$message.error(res.msg)
    63. }
    64. })
    65. }
    66. })
    67. },
    68. }
    69. }
    70. </script>
    71. <style scoped>
    72. /deep/.el-form-item__label{
    73. font-weight: bold;
    74. }
    75. </style>

     Manager.vue:

    1. <template>
    2. <div>
    3. <el-container>
    4. <!-- 侧边栏 -->
    5. <el-aside :width="asideWidth" style="min-height: 100vh; background-color: #001529">
    6. <div style="height: 60px; color: white; display: flex; align-items: center; justify-content: center">
    7. <img src="@/assets/logo1.png" alt="" style="width: 40px; height: 40px">
    8. <span class="logo-title" v-show="!isCollapse">honey2024</span>
    9. </div>
    10. <el-menu :collapse="isCollapse" :collapse-transition="false" router background-color="#001529" text-color="rgba(255, 255, 255, 0.65)" active-text-color="#fff" style="border: none" :default-active="$route.path">
    11. <el-menu-item index="/home">
    12. <i class="el-icon-s-home"></i>
    13. <span slot="title">系统首页</span>
    14. </el-menu-item>
    15. <el-submenu index="info" v-if="user.role === '管理员'">
    16. <template slot="title">
    17. <i class="el-icon-menu"></i>
    18. <span>信息管理</span>
    19. </template>
    20. <el-menu-item index="/user">用户信息</el-menu-item>
    21. </el-submenu>
    22. </el-menu>
    23. </el-aside>
    24. <el-container>
    25. <!-- 头部区域-->
    26. <el-header>
    27. <i :class="collapseIcon" style="font-size: 26px" @click="handleCollapse"></i>
    28. <el-breadcrumb separator-class="el-icon-arrow-right" style="margin-left: 20px">
    29. <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
    30. <el-breadcrumb-item :to="{ path: $route.path }">{{ $route.meta.name }}</el-breadcrumb-item>
    31. </el-breadcrumb>
    32. <div style="flex: 1; width: 0; display: flex; align-items: center; justify-content: flex-end">
    33. <i class="el-icon-quanping" style="font-size: 26px" @click="handleFull"></i>
    34. <el-dropdown placement="bottom">
    35. <div style="display: flex; align-items: center; cursor: default">
    36. <img :src="user.avatar||'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'" alt="" style="width: 40px; height: 40px; margin: 0 5px;border-radius: 50%">
    37. <span>{{user.name}}</span>
    38. </div>
    39. <el-dropdown-menu slot="dropdown">
    40. <el-dropdown-item @click.native="$router.push('/person')">个人信息</el-dropdown-item>
    41. <el-dropdown-item @click.native="$router.push('/password')">修改密码</el-dropdown-item>
    42. <el-dropdown-item @click.native="logout">退出登录</el-dropdown-item>
    43. </el-dropdown-menu>
    44. </el-dropdown>
    45. </div>
    46. </el-header>
    47. <!-- 主体区域-->
    48. <el-main>
    49. <router-view @update:user="updateUser"></router-view>
    50. </el-main>
    51. </el-container>
    52. </el-container>
    53. </div>
    54. </template>
    55. <script>
    56. import axios from "axios";
    57. import request from '@/utils/request'
    58. export default {
    59. name: 'HomeView',
    60. data() {
    61. return {
    62. isCollapse: false, // 不收缩
    63. asideWidth: '200px',
    64. collapseIcon: 'el-icon-s-fold',
    65. user:JSON.parse(localStorage.getItem('honey-user')||'{}'),
    66. }
    67. },
    68. mounted() {
    69. // axios.get('http://localhost:9090/user/selectall').then(res=>{
    70. // console.log(res.data);
    71. // this.users=res.data.data
    72. // })
    73. // request.get('/user/selectall').then(res => {
    74. // this.users = res.data
    75. // })
    76. },
    77. methods: {
    78. updateUser(user){
    79. this.user=JSON.parse(JSON.stringify(user))
    80. },
    81. handleFileUpload(response,file,fileList){
    82. this.fileList=fileList
    83. console.log(response,file,fileList)
    84. },
    85. logout() {
    86. localStorage.removeItem("honey-user")
    87. this.$router.push('/login')
    88. },
    89. handleFull() {
    90. document.documentElement.requestFullscreen()
    91. },
    92. handleCollapse() {
    93. this.isCollapse = !this.isCollapse
    94. this.asideWidth = this.isCollapse ? '64px' : '200px'
    95. this.collapseIcon = this.isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'
    96. }
    97. }
    98. }
    99. </script>
    100. <style>
    101. .el-menu--inline {
    102. background-color: #000c17 !important;
    103. }
    104. .el-menu--inline .el-menu-item {
    105. background-color: #000c17 !important;
    106. padding-left: 49px !important;
    107. }
    108. .el-menu-item:hover, .el-submenu__title:hover {
    109. color: #fff !important;
    110. }
    111. .el-submenu__title:hover i {
    112. color: #fff !important;
    113. }
    114. .el-menu-item:hover i {
    115. color: #fff !important;
    116. }
    117. .el-menu-item.is-active {
    118. background-color: #1890ff !important;
    119. border-radius: 5px !important;
    120. width: calc(100% - 8px);
    121. margin-left: 4px;
    122. }
    123. .el-menu-item.is-active i, .el-menu-item.is-active .el-tooltip {
    124. margin-left: -4px;
    125. }
    126. .el-menu-item {
    127. height: 40px !important;
    128. line-height: 40px !important;
    129. }
    130. .el-submenu__title {
    131. height: 40px !important;
    132. line-height: 40px !important;
    133. }
    134. .el-submenu .el-menu-item {
    135. min-width: 0 !important;
    136. }
    137. .el-menu--inline .el-menu-item.is-active {
    138. padding-left: 45px !important;
    139. }
    140. /*.el-submenu__icon-arrow {*/
    141. /* margin-top: -5px;*/
    142. /*}*/
    143. .el-aside {
    144. transition: width .3s;
    145. box-shadow: 2px 0 6px rgba(0, 21, 41, .35);
    146. }
    147. .logo-title {
    148. margin-left: 5px;
    149. font-size: 20px;
    150. transition: all .3s; /* 0.3s */
    151. }
    152. .el-header {
    153. box-shadow: 2px 0 6px rgba(0, 21, 41, .35);
    154. display: flex;
    155. align-items: center;
    156. }
    157. </style>

    login.vue:

    1. <template>
    2. <div style="display: flex;align-items: center;justify-content: center;background-color: aquamarine;height: 100vh;">
    3. <div style="display: flex;width: 50%;background-color: white;border-radius: 5px;overflow: hidden;">
    4. <div style="flex: 1;">
    5. <img src="@/assets/login.png" alt="" style="width: 100%;">
    6. </div>
    7. <div style="flex: 1;display: flex;align-items: center;justify-content: center;">
    8. <el-form :model="user" style="width: 80%;" :rules="rules" ref="loginRef">
    9. <div style="font-weight: bold; font-size: 20px;margin-bottom: 20px;text-align: center;">
    10. 欢迎登陆后台管理系统
    11. </div>
    12. <el-form-item prop="username">
    13. <el-input placeholder="请输入用户名" v-model="user.username" prefix-icon="el-icon-user"></el-input>
    14. </el-form-item>
    15. <el-form-item prop="password">
    16. <el-input placeholder="请输入密码" v-model="user.password" show-password prefix-icon="el-icon-lock"></el-input>
    17. </el-form-item>
    18. <el-form-item prop="code">
    19. <div style="display: flex;">
    20. <el-input prefix-icon="el-icon-circle-check" v-model="user.code"></el-input>
    21. <div style="flex: 1;height: 32px"><valid-code @update:value="getCode"></valid-code></div>
    22. </div>
    23. </el-form-item>
    24. <el-form-item>
    25. <el-button type="primary" style="width: 100%;" @click="login">登录</el-button>
    26. </el-form-item>
    27. <div style="display: flex;">
    28. <div style="flex: 1;">还没有账号?去<span style="color:aquamarine;cursor: pointer;" @click="$router.push('/register')">注册</span></div>
    29. <div style="flex: 1;text-align: right;cursor: pointer;color: aquamarine;" @click="handleForgetPass">忘记密码</div>
    30. </div>
    31. </el-form>
    32. </div>
    33. </div>
    34. <el-dialog title="忘记密码" :visible.sync="forgetPassDialogVis" width="30%">
    35. <el-form :model="forgetUserForm" label-width="80px" style="padding-right: 20px">
    36. <el-form-item label="用户名">
    37. <el-input v-model="forgetUserForm.username" autocomplete="off"></el-input>
    38. </el-form-item>
    39. <el-form-item label="手机号">
    40. <el-input v-model="forgetUserForm.phone" autocomplete="off"></el-input>
    41. </el-form-item>
    42. </el-form>
    43. <div slot="footer" class="dialog-footer">
    44. <el-button @click="forgetPassDialogVis = false">取 消</el-button>
    45. <el-button type="primary" @click="resetPassword">确 定</el-button>
    46. </div>
    47. </el-dialog>
    48. </div>
    49. </template>
    50. <script>
    51. import ValidCode from "@/components/ValidCode.vue";
    52. export default {
    53. name:'login',
    54. components:{
    55. ValidCode
    56. },
    57. data() {
    58. const validateCode = (rule, value, callback) => {
    59. if (value === '') {
    60. callback(new Error('请输入验证码'));
    61. } else if(value.toLowerCase() !== this.code){
    62. callback(new Error('验证码错误'));
    63. } else {
    64. callback();
    65. }
    66. };
    67. return {
    68. forgetUserForm:{
    69. },
    70. forgetPassDialogVis:false,
    71. code:'',
    72. user: {
    73. code:'',
    74. username: '',
    75. password: ''
    76. },
    77. rules:{
    78. username:[{
    79. required:'true',message:'请输入账号',trigger:'blur'
    80. }],
    81. password:[{
    82. required:'true',message:'请输入密码',trigger:'blur'
    83. }],
    84. code:[{
    85. validator:validateCode,trigger:'blur'
    86. }]
    87. },
    88. }
    89. },
    90. methods:{
    91. handleForgetPass(){
    92. this.forgetUserForm={}
    93. this.forgetPassDialogVis=true
    94. },
    95. getCode(code){
    96. this.code=code.toLowerCase()
    97. },
    98. resetPassword(){
    99. this.$request.put('/password',this.forgetUserForm).then(res=>{
    100. if(res.code==='200'){
    101. this.$message.success('密码重置成功')
    102. this.forgetPassDialogVis=false
    103. }else{
    104. this.$message.error(res.msg)
    105. }
    106. })
    107. },
    108. login(){
    109. this.$refs['loginRef'].validate((valid=>{
    110. if(valid){
    111. this.$request.post("/login",this.user).then(res=>{
    112. if(res.code === '200'){
    113. this.$router.push('/')
    114. this.$message.success('登录成功')
    115. localStorage.setItem('honey-user',JSON.stringify(res.data))
    116. }else{
    117. this.$message.error(res.msg)
    118. }
    119. console.log(res);
    120. })
    121. }
    122. }))
    123. }
    124. }
    125. }
    126. </script>
    127. <style scoped></style>

    后端部分 

    只需要为忘记密码编写一个新接口即可:

     WebController:

    1. package com.example.springboot.controller;
    2. import cn.hutool.core.util.StrUtil;
    3. import com.example.springboot.common.AuthAccess;
    4. import com.example.springboot.common.Result;
    5. import com.example.springboot.entity.User;
    6. import com.example.springboot.exception.ServiceException;
    7. import com.example.springboot.service.UserService;
    8. import org.springframework.web.bind.annotation.*;
    9. import javax.annotation.Resource;
    10. @RestController
    11. public class WebController {
    12. @Resource
    13. UserService userService;
    14. @AuthAccess
    15. @GetMapping("/")
    16. public Result hello(){
    17. return Result.success("success");
    18. }
    19. @PostMapping("/login")
    20. public Result login(@RequestBody User user){
    21. if(StrUtil.isBlank(user.getUsername())||StrUtil.isBlank(user.getPassword())){
    22. return Result.error("数据输入错误");
    23. }
    24. user=userService.login(user);
    25. return Result.success(user);
    26. }
    27. @AuthAccess
    28. @PostMapping("/register")
    29. public Result register(@RequestBody User user){
    30. if(StrUtil.isBlank(user.getUsername())||StrUtil.isBlank(user.getPassword())){
    31. throw new ServiceException("输入不合法");
    32. }
    33. if(user.getUsername().length()>10||user.getPassword().length()>20){
    34. throw new ServiceException("长度过长");
    35. }
    36. user=userService.register(user);
    37. return Result.success(user);
    38. }
    39. @AuthAccess
    40. @PutMapping("/password")
    41. public Result password(@RequestBody User user){
    42. if(StrUtil.isBlank(user.getUsername())||StrUtil.isBlank(user.getPhone())){
    43. throw new ServiceException("输入不合法");
    44. }
    45. userService.resetPassword(user);
    46. return Result.success();
    47. }
    48. }

     UserService:

    1. package com.example.springboot.service;
    2. import com.example.springboot.entity.User;
    3. import com.example.springboot.exception.ServiceException;
    4. import com.example.springboot.mapper.UserMapper;
    5. import com.example.springboot.utils.TokenUtils;
    6. import jdk.nashorn.internal.parser.Token;
    7. import org.springframework.beans.factory.annotation.Autowired;
    8. import org.springframework.stereotype.Service;
    9. import org.springframework.web.bind.annotation.RequestBody;
    10. import java.util.List;
    11. @Service
    12. public class UserService {
    13. @Autowired
    14. UserMapper userMapper;
    15. public void insertUser(User user){
    16. userMapper.insert(user);
    17. }
    18. public void updateUser(User user) {
    19. userMapper.updateUser(user);
    20. }
    21. public void deleteUser(Integer id) {
    22. userMapper.deleteUser(id);
    23. }
    24. public void batchdeleteUser(List ids) {
    25. for(Integer id : ids){
    26. userMapper.deleteUser(id);
    27. }
    28. }
    29. public List<User> selectall() {
    30. return userMapper.selectall();
    31. }
    32. public User selectbyid(Integer id) {
    33. return userMapper.selectbyid(id);
    34. }
    35. public List<User> selectbyname(String name) {
    36. return userMapper.selectbyname(name);
    37. }
    38. public List<User> selectbymore(String username, String name) {
    39. return userMapper.selectbymore(username,name);
    40. }
    41. public List<User> selectbymo(String username, String name) {
    42. return userMapper.selectbymo(username,name);
    43. }
    44. public User login(User user) {
    45. User dbuser=userMapper.selectbyUsername(user.getUsername());
    46. if(dbuser == null){
    47. throw new ServiceException("账号不存在");
    48. }
    49. if(!user.getPassword().equals(dbuser.getPassword())){
    50. throw new ServiceException("账号或者密码错误");
    51. }
    52. String token=TokenUtils.createToken(dbuser.getId().toString(),dbuser.getPassword());
    53. dbuser.setToken(token);
    54. return dbuser;
    55. }
    56. public User register(User user) {
    57. User dbuser=userMapper.selectbyUsername(user.getUsername());
    58. if(dbuser != null){
    59. throw new ServiceException("用户名已存在");
    60. }
    61. userMapper.insert(user);
    62. return user;
    63. }
    64. public void resetPassword(User user) {
    65. User dbuser=userMapper.selectbyUsername(user.getUsername());
    66. if(dbuser==null){
    67. throw new ServiceException("用户不存在");
    68. }
    69. if(!user.getPhone().equals(dbuser.getPhone())){
    70. throw new ServiceException("验证错误");
    71. }
    72. dbuser.setPassword("123");
    73. userMapper.updateUser(dbuser);
    74. }
    75. }

  • 相关阅读:
    抽象工厂设计模式是什么?什么是 Abstract Factory 抽象工厂设计模式?Python 抽象工厂设计模式示例代码
    JAVA赋值不使用引用的办法
    记参加Microsoft Ignite 大会和北京CSDN创作者之夜
    局域网https自签名教程
    问遍了身边的面试官朋友,我整理出这份 Java 集合高频面试题(2021年最新版)
    记一次生产事故的排查与优化——Java服务假死
    3 OpenCV两张图片实现稀疏点云的生成
    尚医通_第12章_用户平台首页数据
    【C++】:关键字+命名空间+输入输出+缺省参数+函数重载+引用
    Prometheus、Grafana安装-部署-监控linux
  • 原文地址:https://blog.csdn.net/m0_74924621/article/details/137930420