java+ai 全栈项目

前端路由vs后端路由:

后端路由:以前网页跳转: 点击链接 → 浏览器发请求给服务器 服务器找到对应页面文件,返回给浏览器 → 整个页面刷新

缺点:页面全部刷新,卡顿,体验差。

前端路由:页面跳转不向服务器请求新页面,浏览器不整体刷新,只局部切换组件。 整个项目只有一份 index.html,所有页面切换都在浏览器内部由 JS 控制。

然后就是前端路由的两种模式:

hash模式和history模式,

(hash模式刷新不会404的原因是因为#后面的(包括#)不会返回给服务端,这样的话就算找不到相应需要切换的文件也不会报错,相反history模式就直接全部返回给服务端查找,找不到就返回给客户端报错的404)

嵌套路由:

eg

两者都有相同的essentials前缀,可以想象浏览器上的文档,旁边的目录里包括了很多部分,点击的时候就会进行界面的刷新切换,目录就是一个组件(相当于这里的essentials),旁边就是其他的组件(essentials后面的路径)。

@路经,

复制代码
//@路径别名简化了导入文件的路劲(src/..../components),
import Backendlayout from '@/components/Backendlayout.vue'

这个@只是方便了我们开发时,在导入路径的时候从头写到尾,避免写漏,但是它实际上是空的,需要我们再单独配置

路由配置简单代码实现,注意子路由前面不要/,不然拼接到根目录了而没有和/back拼接,也就没有子界面

复制代码
import { createRouter, createWebHashHistory } from 'vue-router'
//@路径别名简化了导入文件的路劲(src/..../components),
import Backendlayout from '@/components/Backendlayout.vue'

//路由配置
const routes = [
  {
    path: '/back',
    component: Backendlayout,
    //子路由配置也必须是数组
       children:[
        {
          path:'home',
          component: () => import('@/views/Home.vue')
        }
    ]
  }
]
//创建路由实例
const router=createRouter({
  history:createWebHashHistory(),
  routes
})
//导出路由实例
export default router

vue3:

定位:前端开发框架 作用:提供语法、响应式、路由、组件系统、生命周期等所有基础能力,用来搭建整个网站。 没有 Vue3,你都没法写.vue 文件、无法使用组件。

类比:房子建造全套施工标准、工具、图纸规范

layout:

定位:页面布局容器(组件) 作用:页面外层通用骨架,一般包含头部、侧边栏、主体内容区、底部。 多个页面共用这层外壳,只更换中间主体内

()登录界面的Axios二次封装和接口的调用,通过请求拦截器自动注入token,通过响应拦截器统一处理状态码 :

首先是对于这里的token理解,由于http协议并不会记住刚才登录的人是你。如果没有任何凭证,后端会一脸懵,也就是说登录并验证通过只是一时的,后续的数据发送还需要通过一个验证来保持你的登录状态,这就是token

token不是固定一个的,而且它是有生命周期的,当token失效的时候 说明你要重新进新登录操作。

这一块的功能主要是前后端交互的数据流,进行从浏览器发请求 -> 到 Vite 代理 -> 到后端 -> 再返回浏览器,这叫一次完整的 HTTP 请求生命周期

首先是login文件里的代码

复制代码
<template>
    <div class="container">
        <div class="title">
            <div class="back-home">
                <el-icon><Back /></el-icon>
                <span>返回首页</span>
            </div>    
            <div class="title-text">
                <h2>登录您的账户</h2>
                <p>请输入您的登录信息</p>
            </div>
        </div>
        <div class="from-container">
            <el-form ref="ruleFormRef" :model="formData" :rules="rules" label-position="top">
                <el-form-item label="用户名或邮箱" prop="username">
                    <el-input v-model="formData.username" size="large" placeholder="请输入用户名或邮箱" />
                </el-form-item>
                <el-form-item label="密码" prop="password">
                    <el-input v-model="formData.password" size="large" type="password" show-password placeholder="请输入密码" />
                </el-form-item>
                <el-button class="btn" size="large" type="primary" @click="submitForm(ruleFormRef)">登录</el-button>
            </el-form>
            <div class="footer">
                <p>还没有账户?<router-link to="/auth/register">去注册</router-link></p>
            </div>
        </div>
    </div>
</template>
<script setup>
import {ref,reactive} from'vue'
//引入登录接口
import {login} from '@/api/admin'
const ruleFormRef= ref()
const formData= reactive({
    username:'',
    password:''
})
const rules= reactive({
    username:[
        {required: true, message:'请输入用户名',trigger: 'blur'}
    ],
    password:[
        { required: true,message:'请输入密码',trigger:'blur'}
    ]
})
const submitForm= async(formEl)=>{
    if(!formEl) return
    //登录校验函数
    await formEl.validate((valid, fields)=>{
        //校验通过 表示存在 后续调用接口
        if(valid){
            login(formData).then(data =>{
                if(!data.token) {
                    return console.error('登录失败')
                }
                //登录成功,保存token和用户信息
                localStorage.setItem('token',data.token)
                localStorage.setItem('userInfo',JSON.stringify(data.userInfo))
            })

        }
    })
}

这里主要是读取输入框用户的账号和姓名的逻辑,在script里导入

这两个是响应式工具,

这个数组formData负责存储用户的账户和密码

表单验证规则 true表示必须填写,如果不填写就会出现相应的提示,trigger表示失去焦点时触发验证(也就是从输入框点出去的那一刻)

效果:

这里进行数据的接收和发送,login方法我们封装在admin文件中

submitForm是一个异步函数(不会等耗时操作完成,先继续跑后面代码,等耗时任务完成之后,再回来处理结果

这里是进行表单验证,但是还没写先不管

接着就是先通过valid验证是否都填入 然后往login里面传入数组(formData),发送完 then执行接收后端传来的data数据,并取出数据里的token进行校验,若存在即说明有这个客户就通过

login里的样式:

复制代码
</script>
<style scoped lang="scss">
    .container{ 
        width:384px;
        .title{
            .back-home{
                margin-bottom: 60px;
            }
            .title-text{
                text-align: center;
                h2{
                    font-size: 36px;
                    margin-bottom: 10px;
                }
                p{
                    font-size: 18px;
                    color:#6b7280;
                }
            }
        }
    }
    .from-container{
        margin-top: 30px;
        .btn{
            margin-top: 40px;
            width: 100%;
        }
        .footer{
            padding: 30px;
            text-align:center;
        }
    }
</style>

接着讲解request文件的逻辑:

复制代码
import axios from 'axios'
import {ElMessage} from 'element-plus'
//创建axios实例
const service = axios.create({
    baseURL: '/api',
    //请求超时时间
    timeout: 5000,
})
//请求拦截器
service.interceptors.request.use(
    config => {
        //在发送请求之前做些什么
        const token = localStorage.getItem('token')
        //如果存在token,就添加到请求头中
        if(token){
            config.headers['token']= token
        }
        return config
    },
    (error) => {
        //对请求错误做些什么
        return Promise.reject(error)
    }
)
//响应拦截器
service.interceptors.response.use(
    response => {
        //对响应数据做点什么
        const{data,config}=response
        if(data.code==='200'){
            return data.data
        }else{
            if(data.code==='-1'){
                if(!config.url.includes('/login')){
                    ElMessage.error(data.msg||'登录过期,请重新登录')
                    //清楚登录信息
                    localStorage.removeItem('token')
                    localStorage.removeItem('userInfo')
                    window.location.href='/auth/login'
                    router.push('/auth/login')
                }
            }else{
                ElMessage.error(data.msg||'登录过期,请重新登录')
                return Promise.reject('网络请求失败....')
            }
        }
        return response
    },
    (error) => {
        //对响应错误做点什么
        return Promise.reject(error)
    }
)
//暴露axios实例对象
export default service

主题是两个拦截器,请求和响应的,开头我们需要创建axios对象

也就是说没有axios只能停留在javaScript变量层面,数据也发不出收不到。

请求拦截器的触发一般是我们在login传入数组后,service准备在admin里post发送数据,但是发送前会对数据进行配置,首先就是地址

在这个代码里

先获取磁盘中是否有存入token,如果有就直接用,要是有其他错误就直接报错

最后这一句至关重要,他的意思是对所有文件进行暴露,也就是所有文件可以用这个request文件

相关推荐
Nil2081 小时前
leetcode 79单词搜索
开发语言·c#
Blockchina1 小时前
AI Agent 写权限安全吗?Codex、Claude Code 与 GitHub Copilot 最小权限实战指南
开发语言·php
阿维的博客日记1 小时前
Example API指南2
java·mybatis
ctlover1 小时前
网络编程和多线程
开发语言·网络·python
神仙别闹1 小时前
基于C#实现(WinForm)文件管理系统
java·开发语言·c#
Mr_liu_6661 小时前
ns3-gym例子解析_基础例子与wifi例子_DQN(3)
开发语言·c++·python·dqn·ns3
weixin_440730501 小时前
playwright实战-渠道应用操作
开发语言·前端·python
砚底藏山河1 小时前
存储选型实战:CSV-SQLite-MySQL同机基准(魔码量化实战 #02)
java·数据库·python·金融·maven
huaweichenai1 小时前
spring boot 打包并部署到线上服务
java·数据库·spring boot