Controller
package com.example.springboot.controller;

import com.example.springboot.entity.Employee;
import com.example.springboot.service.EmployeeService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/employee")
public class EmployeeController {

    @Resource
    private EmployeeService employeeService;

    @PostMapping("/register")
    public String register(@RequestBody Employee employee) {
        return employeeService.register(employee);
    }

    @PostMapping("/login")
    public Map<String, Object> login(@RequestParam String username, @RequestParam String password) {
        Map<String, Object> result = new HashMap<>();
        Employee employee = employeeService.getByUsername(username);
        if (employee != null && employeeService.verifyPassword(password, employee.getPassword())) {
            result.put("code", 200);
            result.put("message", "登录成功");
            result.put("data", Map.of(
                    "id", employee.getId(),
                    "name", employee.getUsername()
            ));
        } else {
            result.put("code", 401);
            result.put("message", "用户名或密码错误");
        }
        return result;
    }


    @PostMapping("/reset-password")
    public String resetPassword(@RequestParam String username,
                                @RequestParam String phone,
                                @RequestParam String newPassword) {
        return employeeService.resetPassword(username, phone, newPassword);
    }
    @GetMapping("/info")
    public Map<String, Object> getUserInfo(@RequestParam Integer id) {
        Employee employee = employeeService.getById(id);
        Map<String, Object> result = new HashMap<>();
        if (employee != null) {
            result.put("name", employee.getUsername());
        } else {
            result.put("name", "未知用户");
        }
        return result;
    }
}

Employee

Mappackage com.example.springboot.entity;

public class Employee {
    private Integer id;
    private String username;
    private String password;
    private String phone;

    // Getters & Setters
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }

    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }

    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }

    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }
}
mapper
package com.example.springboot.mapper;

import com.example.springboot.entity.Employee;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface EmployeeMapper {

    void insert(Employee employee);

    Employee findByUsername(String username);

    Employee findByUsernameAndPhone(String username, String phone);

    void updatePassword(String username, String newPassword);

    Employee findById(Integer id);

}

Service
package com.example.springboot.service;

import com.example.springboot.entity.Employee;
import com.example.springboot.mapper.EmployeeMapper;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import jakarta.annotation.Resource;

@Service
public class EmployeeService {

    @Resource
    private EmployeeMapper employeeMapper;

    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    public String register(Employee employee) {
        // 禁止注册 admin 用户名
        if ("admin".equalsIgnoreCase(employee.getUsername())) {
            return "禁止注册管理员账户";
        }

        if (employee.getUsername().length() != 6 || employee.getPassword().length() != 8 || employee.getPhone().length() != 11) {
            return "输入信息格式不正确";
        }

        employee.setPassword(passwordEncoder.encode(employee.getPassword()));
        employeeMapper.insert(employee);
        return "注册成功";
    }


    public boolean login(String username, String rawPassword) {
        if ("admin1".equalsIgnoreCase(username)) {
            return "12345678".equals(rawPassword);  // 简单判断
        }

        Employee dbUser = employeeMapper.findByUsername(username);
        return dbUser != null && passwordEncoder.matches(rawPassword, dbUser.getPassword());
    }


    public String resetPassword(String username, String phone, String newPassword) {
        if (newPassword.length() != 8) {
            return "密码长度必须为8位";
        }

        Employee employee = employeeMapper.findByUsernameAndPhone(username, phone);
        if (employee == null) {
            return "用户名或手机号不匹配";
        }

        String encodedPassword = passwordEncoder.encode(newPassword);
        employeeMapper.updatePassword(username, encodedPassword);
        return "密码已重置";
    }

    // 根据id查询员工
    public Employee getById(Integer id) {
        return employeeMapper.findById(id);
    }

     // 根据用户名查询员工

    public Employee getByUsername(String username) {
        if ("admin1".equalsIgnoreCase(username)) {
            Employee admin = new Employee();
            admin.setId(0); // 不影响数据库主键
            admin.setUsername("admin1");
            admin.setPassword(passwordEncoder.encode("12345678"));
            return admin;
        }
        return employeeMapper.findByUsername(username);
    }



    // 验证密码
    public boolean verifyPassword(String rawPassword, String encodedPassword) {
        if ("admin1".equals(rawPassword) && passwordEncoder.matches("12345678", encodedPassword)) {
            return true;
        }
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }



}

Mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.springboot.mapper.EmployeeMapper">

    <insert id="insert" parameterType="com.example.springboot.entity.Employee">
        INSERT INTO employee (username, password, phone)
        VALUES (#{username}, #{password}, #{phone})
    </insert>

    <select id="findByUsername" resultType="com.example.springboot.entity.Employee">
        SELECT * FROM employee WHERE username = #{username}
    </select>

    <select id="findByUsernameAndPhone" resultType="com.example.springboot.entity.Employee">
        SELECT * FROM employee WHERE username = #{username} AND phone = #{phone}
    </select>

    <update id="updatePassword">
        UPDATE employee SET password = #{newPassword} WHERE username = #{username}
    </update>

    <select id="findById" resultType="com.example.springboot.entity.Employee">
        SELECT * FROM employee WHERE id = #{id}
    </select>

</mapper>

Login.vue
<template>
  <div class="login-container">
    <div class="login-form">
      <h2 style="text-align: center;">登录</h2>
      <form @submit.prevent="handleLogin">
        <div class="input-group">
          <label for="username">用户名：</label>
          <input type="text" id="username" v-model="username" required />
        </div>
        <div class="input-group">
          <label for="password">密码：</label>
          <input type="password" id="password" v-model="password" required />
        </div>
        <button type="submit">登录</button>
        <div class="register-link">
          <p>没有账号？<a href="#" @click.prevent="$router.push('/register')">立即注册</a></p>
        </div>
        <div class="forgot-password-link">
          <p><a href="#" @click.prevent="$router.push('/reset-password')">忘记密码？</a></p>
        </div>

      </form>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'

const username = ref('')
const password = ref('')
const router = useRouter()

const handleLogin = async () => {
  if (username.value.length !== 6 || password.value.length !== 8) {
    alert('请输入6位用户名和8位密码')
    return
  }

  const url = `http://localhost:8080/employee/login?username=${username.value}&password=${password.value}`

  try {
    const res = await fetch(url, { method: 'POST' })
    const data = await res.json()  // 解析 JSON 响应

    if (data.code === 200) {
      // 登录成功，保存 userId
      localStorage.setItem('userId', data.data.id)
      alert(data.message)
      // 保存用户名（重点，没有这个admin页面进不去）
      localStorage.setItem('username', username.value)
      // 判断是否为管理员账号
      if (username.value.toLowerCase() === 'admin1') {
        router.push('/admin')  // 跳转管理员页面
      } else {
        router.push('/')       // 跳转普通首页
      }
    } else {
      alert(data.message || '登录失败')
    }

  } catch (error) {
    alert('登录请求失败')
    console.error(error)
  }
}
</script>

















<style scoped>
.login-container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background-image: url('@/assets/login-background.png');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}


.login-form {
  width: 400px;
  padding: 80px;
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);

}

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

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

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

button {
  width: 420px;
  padding: 10px;
  background-color: #559ef1;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  margin-top: 10px;
}

button:hover {
  background-color: #4cb1dc;
}

.register-link {
  margin-top: 15px;
  text-align: center;
  font-size: 14px;
}

.register-link a {
  color: #42b983;
  text-decoration: none;
}

.register-link a:hover {
  text-decoration: underline;
}

.forgot-password-link {
  margin-top: 10px;
  text-align: center;
  font-size: 14px;
}

.forgot-password-link a {
  color: #3498db;
  text-decoration: none;
}

.forgot-password-link a:hover {
  text-decoration: underline;
}

</style>

Register.vue
<template>
  <div class="register-container">
    <div class="register-form">
      <h2 style="text-align: center;">注册</h2>
      <form @submit.prevent="handleRegister">
        <div class="input-group">
          <label for="username">用户名：</label>
          <input type="text" id="username" v-model="form.username" required />
        </div>
        <div class="input-group">
          <label for="phone">电话：</label>
          <input type="text" id="phone" v-model="form.phone" required />

        </div>
        <div class="input-group">
          <label for="password">密码：</label>
          <input type="password" id="password" v-model="form.password" required />
        </div>
        <div class="input-group">
          <label for="confirmPassword">确认密码：</label>
          <input type="password" id="confirmPassword" v-model="form.confirmPassword" required />
        </div>
        <button type="submit">注册</button>
        <div class="login-link">
          <p>已有账号？<a href="#" @click.prevent="$router.push('/login')">立即登录</a></p>
        </div>
      </form>
    </div>
  </div>
</template>

<script setup>
import { reactive } from 'vue'
import { useRouter } from 'vue-router'

const router = useRouter()

const form = reactive({
  username: '',
  phone: '',
  password: '',
  confirmPassword: ''
})

const handleRegister = async () => {
  const usernameLower = form.username.toLowerCase()

  // 禁止包含 admin 相关用户名
  if (usernameLower === 'admin' || /^admin\d*$/.test(usernameLower)) {
    alert('禁止注册管理员相关用户名')
    return
  }
  // 基本表单校验
  if (form.username.length !== 6) {
    alert('用户名必须是6位')
    return
  }
  if (form.phone.length !== 11 || !/^\d{11}$/.test(form.phone)) {
    alert('请输入11位手机号')
    return
  }
  if (form.password.length !== 8) {
    alert('密码必须是8位')
    return
  }
  if (form.password !== form.confirmPassword) {
    alert('两次输入的密码不一致')
    return
  }

  // 发起注册请求
  try {
    const res = await fetch('http://localhost:8080/employee/register', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        username: form.username,
        password: form.password,
        phone: form.phone
      })
    })

    const text = await res.text()
    alert(text)

    if (text === '注册成功') {
      router.push('/login')
    }
  } catch (error) {
    console.error('注册失败:', error)
    alert('注册请求失败，请稍后再试')
  }
}
</script>




<style scoped>
.register-container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background-image: url('@/assets/login-background.png');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.register-form {
  width: 400px;
  padding: 80px;
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
}

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

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

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

button {
  width: 420px;
  padding: 10px;
  background-color: #559ef1;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  margin-top: 10px;
}

button:hover {
  background-color: #4cb1dc;
}

.login-link {
  margin-top: 15px;
  text-align: center;
  font-size: 14px;
}

.login-link a {
  color: #42b983;
  text-decoration: none;
}

.login-link a:hover {
  text-decoration: underline;
}
</style>

Reset-password.vue
<template>
  <div class="reset-password-container">
    <div class="reset-password-form">
      <h2 style="text-align: center;">重置密码</h2>
      <form @submit.prevent="handleResetPassword">
        <div class="input-group">
          <label for="username">用户名：</label>
          <input type="text" id="username" v-model="username" required />
        </div>
        <div class="input-group">
          <label for="phone">电话：</label>
          <input type="tel" id="phone" v-model="phone" required />
        </div>
        <button type="submit">重置密码</button>
        <div class="login-link">
          <p>已有账号？<a href="#" @click.prevent="$router.push('/login')">立即登录</a></p>
        </div>
      </form>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'

const username = ref('')
const phone = ref('')
const router = useRouter()

const handleResetPassword = async () => {
  const newPassword = prompt('请输入新的8位密码：')
  if (!newPassword || newPassword.length !== 8) {
    alert('密码长度必须为8位')
    return
  }

  const url = `http://localhost:8080/employee/reset-password?username=${username.value}&phone=${phone.value}&newPassword=${newPassword}`

  try {
    const res = await fetch(url, { method: 'POST' })
    const text = await res.text()
    alert(text)
    if (text === '密码已重置') {
      router.push('/login')
    }
  } catch (error) {
    alert('重置失败')
    console.error(error)
  }
}
</script>



<style scoped>
.reset-password-container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background-image: url('@/assets/login-background.png');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.reset-password-form {
  width: 400px;
  padding: 80px;
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
}

h2 {
  text-align: center;
  margin-bottom: 30px;
  font-size: 24px;
  color: #333;
}

.input-group {
  margin-bottom: 20px;
}

label {
  display: block;
  font-weight: 600;
  margin-bottom: 8px;
  color: #444;
}

input[type="text"],
input[type="tel"] {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid #ccc;
  border-radius: 8px;
  font-size: 14px;
  transition: border 0.2s;
}

input:focus {
  border-color: #559ef1;
  outline: none;
}

button {
  width: 420px;
  padding: 12px;
  background-color: #559ef1;
  color: white;
  border: none;
  border-radius: 8px;
  font-size: 16px;
  font-weight: bold;
  cursor: pointer;
  transition: background-color 0.3s;
}

button:hover {
  background-color: #3d8fe3;
}

.login-link {
  margin-top: 20px;
  text-align: center;
  font-size: 14px;
  color: #666;
}

.login-link a {
  color: #42b983;
  text-decoration: none;
}

.login-link a:hover {
  text-decoration: underline;
}
</style>



Admin.vue
<template>
  <div class="admin-page">
    <!-- 头部开始 -->
    <header class="admin-header">
      <!-- 左侧 logo + 标题 -->
      <div class="header-left">
        <img src="@/assets/logo.png" class="logo" />
        <span class="title">背多分管理员后台</span>
      </div>
      <!-- 右侧 用户名 + 退出按钮 -->
      <div class="header-right">
        <span class="username">欢迎，{{ username }}</span>
        <el-button @click="logout" type="info" size="small" plain>登录/退出</el-button>
      </div>
    </header>
    <!-- 头部结束 -->

    <!-- 页面主体开始 -->
    <div class="admin-main">
      <!-- 左侧导航 -->
      <aside class="admin-sidebar">
        <el-menu
            router
            :default-active="$route.path"
            class="sidebar-menu"
        >
          <el-menu-item index="/admin/dashboard">
            <el-icon><HomeFilled /></el-icon>
            <span>控制面板</span>
          </el-menu-item>
          <el-menu-item index="/admin/users">
            <el-icon><Document /></el-icon>
            <span>用户管理</span>
          </el-menu-item>
          <el-menu-item index="/admin/words">
            <el-icon><Document /></el-icon>
            <span>词库管理</span>
          </el-menu-item>
        </el-menu>
      </aside>
      <!-- 主体内容 -->
      <main class="admin-content">
        <RouterView />
      </main>
    </div>
    <!-- 页面主体结束 -->
  </div>
</template>

<script setup>
// 引入图标
import { HomeFilled, Document } from '@element-plus/icons-vue'
// 引入路由
import { useRouter } from 'vue-router'
// 响应式变量和生命周期
import { ref, onMounted } from 'vue'
// axios 请求
import axios from 'axios'

const username = ref('加载中...')
const router = useRouter()
const userId = localStorage.getItem('userId')

const logout = () => {
  localStorage.removeItem('userId');
  localStorage.removeItem('username');
  localStorage.clear()
  router.push('/login');
}


const fetchUserInfo = async () => {
  if (!userId || isNaN(userId)) {
    username.value = '未登录'
    return
  }

  try {
    const response = await axios.get('http://localhost:8080/employee/info', {
      params: { id: userId }
    })
    if (response.data && response.data.name) {
      username.value = response.data.name
    } else {
      console.warn('响应中未包含用户名:', response.data)
      username.value = '未知用户'
    }
  } catch (error) {
    console.error('获取用户信息失败:', error)
    username.value = '未知用户'
  }
}

onMounted(() => {
  username.value = '管理员'
})

</script>

<style scoped>
.admin-header {
  height: 60px;
  background-color: #6596ff;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 20px;
  color: white;
}

.header-left {
  display: flex;
  align-items: center;
}

.logo {
  width: 40px;
  height: 40px;
  margin-right: 10px;
}

.title {
  font-size: 24px;
  font-weight: bold;
}

.header-right {
  display: flex;
  align-items: center;
}

.username {
  margin-right: 20px;
}

.admin-main {
  display: flex;
  min-height: calc(100vh - 60px);
}

.admin-sidebar {
  width: 200px;
  border-right: 1px solid #ddd;
}

.sidebar-menu {
  border: none;
}

.admin-content {
  flex: 1;
  background-color: #f8f8ff;
  padding: 20px;
}
</style>


路由
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
      // 首页
      {path:'/',  redirect: '/father/LeaningVue'},
      // 登录
      {path: '/login', name: 'login', meta:  {title: '登录'},component: () => import('../views/login.vue'),},
      //  注册
      {path: '/register', name: 'register', meta:  {title: '注册'},component: () => import('../views/register.vue'),},
      //  重置密码
      {path: '/reset-password', name: 'ResetPassword',meta:  {title: '重置密码'}, component: () => import('../views/reset-password.vue')},

      // 父路由
      {path: '/father', name: 'father', component: () => import('../views/father.vue'),children: [
            {path: 'LeaningVue', name: 'LeaningVue', meta:  {title: '学习Vue'},component: () => import('../views/LeaningVue.vue'),},
            {path: 'test', name: 'test', meta:  {title: '测试页面'},component: () => import('../views/test.vue'),},
            {path: 'vocabulary', name: 'vocabulary', meta:  {title: '生词本'},component: () => import('../views/vocabulary.vue'),},
      ]},

      //  管理员
      {path: '/admin', name: 'admin', component: () => import('../views/admin/admin.vue'),children: [
            // {path: 'index', name: 'index', meta:  {title: '管理员首页'},component: () => import('../views/admin/index.vue'),},

          ]},

      // 404
      {path: '/404', name: '找不到', meta:  {title: '404找不到页面'},component: () => import('../views/404.vue'),},
      {path: '/:pathMatch(.*)*', name: '找不到', meta:  {title: '404找不到页面'},component: () => import('../views/404.vue'),},// 该路由用于捕获所有未匹配的路径，重定向到 404 页面

  ]
})

router.beforeEach((to, from, next) => {
    const title = to.meta.title;
    if (title) {
        document.title = title;
    }

    const username = localStorage.getItem('username');
    console.log('路由守卫触发，username:', username);

    // 管理员权限控制
    if (to.path.startsWith('/admin')) {
        if (!username || !/^admin\d*$/.test(username.toLowerCase())) {
            alert('您无权访问该页面');
            return next('/login');
        }
    }

    next();
});


export default router

是怎么做到，我只要登录admin1账号就跳到管理员页面的