springboot+vue显示当前用户功能

现在的前端界面如下图:显示“当前用户”是静态不可修改的,并且没有实现“个人中心”和“退出登录”按钮的逻辑,所以接下来就要对前后端进行修改实现“当前用户”真正显示的是当前用户的名字。

一.简要概述

后端部分:

  1. 用户登录和信息获取 API:

    • 登录认证控制器(例如 AuthController):
      • 确保登录成功后,返回用户的基本信息(如姓名、角色、token等)。
    • 用户信息控制器(例如 UserController):
      • 创建一个 API 来获取当前登录用户的信息,例如 /api/user/me。这个 API 需要返回用户的详细信息,包括姓名、角色等。
    • 安全配置类(例如 SecurityConfig):
      • 配置安全策略以确保只有登录用户可以访问用户信息的 API。
  2. 退出登录 API(可选):

    • 如果你使用会话管理(如 Spring Security),可以创建一个登出 API,清除会话或 token。
    • 如果使用 JWT,通常不需要后端支持的登出逻辑,前端只需清除 token 即可。

前端部分:

  1. 获取并显示用户名:

    • Vuex 状态管理(或类似的全局状态管理):
      • 在登录成功后,将用户的姓名、token 等信息保存到 Vuex 状态管理或 localStorage。
    • 头部组件(Header.vue):
      • mounted 生命周期钩子中,通过 Vuex 或 localStorage 获取用户信息,并将用户名显示在右上角。
  2. 退出登录逻辑:

    • 头部组件(Header.vue):
      • handleCommand 方法中处理登出逻辑,清除 Vuex 或 localStorage 中的用户信息,然后使用 this.$router.push('/login') 跳转到登录页面。

二.后端代码编写

后端中已经编写了登录的方法(根据账号返回User对象),使用gpt让我重新创建一个方法(根据id返回User对象),亲测没用,因为前端在登录的时候就已经获得了对象,所以不用再创建一个方法,controller代码如下:

package com.example.controller;
//登录验证类

import com.example.config.ApiResponse;
import com.example.entity.User;
import com.example.service.UserService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/auth")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/login")
    public ResponseEntity<ApiResponse<?>> login(@RequestBody LoginRequest loginRequest) {
        User user = userService.selectByPhone2(loginRequest.getPhoneNumber());
        if (user != null && userService.checkPassword(loginRequest.getPassword(), user.getUserPassword())) {
            return ResponseEntity.ok(ApiResponse.success("登录成功",user));
        } else {
            return ResponseEntity.status(401).body(ApiResponse.error("登录失败"));
        }
    }

    // 登录请求的内部类
    @Data
    public static class LoginRequest {
        private String phoneNumber;
        private String password;
    }

//    @GetMapping("/profile")
//    public ResponseEntity<ApiResponse<?>> getUserProfile(@RequestParam Integer userId) {
//        User user = userService.selectById2(userId);
//        if (user != null) {
//            return ResponseEntity.ok(ApiResponse.success("获取用户信息成功", user));
//        } else {
//            return ResponseEntity.status(404).body(ApiResponse.error("未找到用户"));
//        }
//    }

}

三.前端代码编写

Login.vue:

<template>
  <div class="login-container">
    <div class="form-container">
      <h2>登录界面</h2>
      <form @submit.prevent="login">
        <div class="form-group">
          <label for="phoneNumber">账号:</label>
          <input
              type="text"
              id="phoneNumber"
              v-model="phoneNumber"
              placeholder="请输入登录账号"
              required
          />
        </div>
        <div class="form-group">
          <label for="password">密码:</label>
          <input
              type="password"
              id="password"
              v-model="password"
              placeholder="请输入密码"
              required
          />
        </div>
        <button type="submit">登录</button>
      </form>
      <p v-if="errorMessage" class="error">{{ errorMessage }}</p>
    </div>
  </div>
</template>


<script>
import axios from 'axios';

export default {
  data() {
    return {
      phoneNumber: '',
      password: '',
      errorMessage: null,
    };
  },
  methods: {
    async login() {
      try {
        const response = await axios.post('http://localhost:8081/api/auth/login', {
          phoneNumber: this.phoneNumber,
          password: this.password,
        });
        // console.log('登录响应:', response.data.data); // 查看响应数据
        // console.log('登录响应:', response.data.data.userName); // 查看响应数据
        if (response.data.success) {
          this.$emit('login-success', {
            picture: response.data.data.userPicture, // 用户头像链接
            name: response.data.data.userName // 用户名字
          });//多返回userPicture和userName,这里是双层数组,使用console.log可以发现
          this.$message.success("登录成功");
        } else {
          this.errorMessage = response.data.message;
        }
      } catch (error) {
        this.errorMessage = '登录失败,请检查账号和密码';
      }
    },
  },
};
</script>

<style scoped>
.login-container {
  position: relative;
  width: auto;
  height: 100vh;
  background-image: url('@/images/2.jpg');
  background-size: cover;
  background-position: center;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  padding-right: 10%;
}

.form-container {
  width: 300px;
  padding: 30px;
  border: 1px solid rgba(0, 0, 0, 0.2); /* 边框颜色也设置为半透明 */
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  background-color: rgba(255, 255, 255, 0.95); /* 使用rgba设置背景色为半透明 */

  position: absolute;
  top: 50%;
  right: 15%;
  transform: translateY(-50%);
}

.form-group {
  margin-bottom: 15px;
}

label {
  display: block;
  margin-bottom: 5px;
  font-weight: bold;
}

input[type="text"],
input[type="password"] {
  width: 100%;
  padding: 8px;
  box-sizing: border-box;
  border: 1px solid #ccc;
  border-radius: 4px;
}

button {
  width: 100%;
  padding: 10px;
  background-color: #007bff;
  color: #fff;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
}

button:hover {
  background-color: #0056b3;
}

.error {
  color: red;
  margin-top: 15px;
  text-align: center;
}
</style>

App.vue

<template>
  <div>
    <el-container v-if="isLoggedIn" style="height: 100%;">
      <el-header style="width: 100% ;padding: 0">
        <Header :userPicture="userPicture" :userName="userName" />
      </el-header>
      <div class="divider"></div> <!-- 分割线 -->
      <el-container style="width: 100%">
        <el-aside width="200px">
          <Sidebar @select="updateContent" />
        </el-aside>
        <el-main>
          <Content :selectedSection="selectedSection" />
        </el-main>
      </el-container>
    </el-container>

    <div v-else>
      <Login @login-success="handleLoginSuccess" />
    </div>
  </div>
</template>

<script>
import Header from './components/Header.vue';
import Sidebar from './components/Sidebar.vue';
import Content from './components/Content.vue';
import Login from './components/Login.vue';

export default {
  components: {
    Header,
    Sidebar,
    Content,
    Login,
  },
  data() {
    return {
      selectedSection: '0',
      isLoggedIn: false, // 登录状态
      userPicture:'', // 用户头像
      userName: '' // 用户名字
    };
  },
  methods: {
    updateContent(index) {
      this.selectedSection = index;
    },
    handleLoginSuccess(userData) {//接收Login返回的数据并传给Header
      this.isLoggedIn = true; // 登录成功后更新状态
      this.userPicture = userData.picture; // 假设 userData 包含头像链接
      this.userName = userData.name; // 假设 userData 包含用户名

      this.$nextTick(() => {
        console.log('头像链接:', this.userPicture); // 查看更新后的数据
        console.log('用户名:', this.userName); // 查看更新后的数据
      });

    }
  }
};
</script>

Header.vue:

<!-- 头部 -->
<template>
  <div class="header">
    <img src="@/images/1.jpg" alt="Logo" class="logo" />
    <div class="title">小菜家教平台</div>
    <el-dropdown @command="handleCommand">
      <span class="el-dropdown-link">
        <img :src="userPicture" class="user-picture" alt="用户头像" />
        {{ userName }}
        <el-icon class="el-icon--right"><arrow-down /></el-icon>
      </span>
      <template #dropdown>
        <el-dropdown-menu>
          <el-dropdown-item command="profile">个人中心</el-dropdown-item>
          <el-dropdown-item command="logout">退出登录</el-dropdown-item>
        </el-dropdown-menu>
      </template>
    </el-dropdown>
  </div>
</template>

<script>
export default {
  props: {
    userPicture: {
      type: String,
      default: () => require('@/images/3.jpg')
    },
    userName: {
      type: String,
      default: '用户'
    }
  },
  methods: {
    handleCommand(command) {
      if (command === 'profile') {
        alert('个人中心');
      } else if (command === 'logout') {
        alert('退出登录');
      }
    }
  },
  mounted() {
    console.log('Header 组件接收到的头像链接:', this.userPicture);
    console.log('Header 组件接收到的用户名:', this.userName);
  }
}
</script>

<style scoped>
.header {
  display: flex;
  justify-content: space-between;
  align-items: center; /* 垂直居中对齐 */
  padding: 0 30px;
  height: 60px; /* 适当调整头部高度 */
  background-color: slateblue;
  box-sizing: border-box; /* 包含边框和内边距在宽度和高度中 */
}

.logo {
  width: 35px;
  height: 35px;
  border-radius: 50%;
  margin-right: 10px;
  border: 1px solid white;
}

.title {
  font-size: 22px;
  font-weight: 700;
  color: white;
  margin-right: auto;
}

.user-picture {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  margin-right: 10px;
  object-fit: cover; /* 确保图片按比例显示 */
}

.el-dropdown-link {
  cursor: pointer;
  color: white;
  display: flex;
  align-items: center;
  font-size: 15px;
}

.el-dropdown-link:focus {
  outline: none;
}
</style>
  • 26
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值