【JAVA全栈项目】弧图图-智能图床 SpringBoot+Vue3 :[框架开荒:一文全步骤打通前后端项目全流程]

文章目录

  • 一、后端框架
    • [1. 依赖版本说明](#1. 依赖版本说明)
    • [2. pom.xml](#2. pom.xml)
    • [3. knife4j配置](#3. knife4j配置)
    • [4. 自定义异常处理](#4. 自定义异常处理)
    • [5. 自定义后端统一请求响应体](#5. 自定义后端统一请求响应体)
    • [6. Mysql连接配置](#6. Mysql连接配置)
    • [7. mybatis-plus配置](#7. mybatis-plus配置)
    • [8. 全局跨域配置](#8. 全局跨域配置)
    • [9. 接口测试](#9. 接口测试)
  • 二、前端框架
    • [1. 依赖版本说明](#1. 依赖版本说明)
    • [2. 快速构建Vue3+TypeScript前端框架](#2. 快速构建Vue3+TypeScript前端框架)
    • [3. 引入组件库 (Ant Design Vue)](#3. 引入组件库 (Ant Design Vue))
    • [4. 开发规范](#4. 开发规范)
    • [5. 修改标签页显示信息](#5. 修改标签页显示信息)
    • [6. 全局通用布局开发](#6. 全局通用布局开发)
    • [7. 建立页面上中下布局结构](#7. 建立页面上中下布局结构)
    • [8. 建立上中下三层布局的公共内容](#8. 建立上中下三层布局的公共内容)
    • [9. 集成Axios](#9. 集成Axios)
    • [10. 使用OpenAPI实现批量生成前端请求接口文件](#10. 使用OpenAPI实现批量生成前端请求接口文件)
    • [11. 引入全局状态管理Pinia](#11. 引入全局状态管理Pinia)
    • [12. 页面国际化设置](#12. 页面国际化设置)

前言:

弧图图GitHub项目地址:https://github.com/whltaoin/hututu

本项目是基于Vue3 + SpringBoot + COS + WebScoket的企业级智能图床平台。

核心功能:

所有用户均可在平台上传和检索图片,可通过网络爬虫一键帮助用户生成需要类型的图片集。

实现图片存储空间

实现多人实时协同设计图片

平台可分为普通用户和企业用户,从而应用不同的权限场景。

一、后端框架

1. 依赖版本说明

SpringBoot版本:2.7.6

JDK:11

MybatisPlus:3.5.14

knife4j:4.4.0

hutool:5.8.38

2. pom.xml

xml 复制代码
 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--切面aop-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--    mybatis-plus说明文档:https://baomidou.com/getting-started/-->

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.14</version>
        </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>

        <!--       接口文档: https://doc.xiaominfo.com/docs/quick-start#spring-boot-2-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
            <version>4.4.0</version>
        </dependency>
        <!--    常用工具类:https://doc.hutool.cn/pages/index/#%F0%9F%93%9A%E7%AE%80%E4%BB%8B-->

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.38</version>
        </dependency>

3. knife4j配置

openApi2.0配置文档:https://doc.xiaominfo.com/docs/quick-start#openapi2

访问Knife4j的文档地址:http://ip:port/doc.html即可查看文档

  1. application.yml
yaml 复制代码
knife4j:
  enable: true # true为开启,false为关闭
  openapi:
    title: 弧图图-智能图床

    email: whltaoin@163.com
    url: htt://www.varin.cn
    version: V1.0.0
    group:
      default:
        group-name: ""
        api-rule: package
        api-rule-resources:
          - cn.varin.hututu.controller

4. 自定义异常处理

  1. 定义自定义响应码枚举:ResponseCode
java 复制代码
package cn.varin.hututu.exception;

import lombok.Getter;

/**
 * 请求响应码
 */

@Getter
public enum ResponseCode {
    SUCCESS(200, "ok"),
    PARAMS_ERROR(40000, "请求参数错误"),
    NOT_LOGIN_ERROR(40100, "未登录"),
    NO_AUTH_ERROR(40101, "无权限"),
    NOT_FOUND_ERROR(40400, "请求数据不存在"),
    FORBIDDEN_ERROR(40300, "禁止访问"),
    SYSTEM_ERROR(50000, "系统内部异常"),
    OPERATION_ERROR(50001, "操作失败");
    private final  int code;
    private final String  message;

     ResponseCode(int code, String message) {
        this.code = code;
        this.message = message;
    }


}
  1. 自定义异常类:CustomizeExcaption
java 复制代码
package cn.varin.hututu.exception;


import lombok.Getter;

/**
 * 自定义异常类
 */
@Getter

public class CustomizeException extends RuntimeException {
    private final Integer code;
    public CustomizeException(Integer code,String message ) {
        super(message);
        this.code = code;
    }

    public CustomizeException(ResponseCode responseCode ) {
        super(responseCode.getMessage());
        this.code = responseCode.getCode();
    }
    public CustomizeException(ResponseCode responseCode ,String message) {
        super(message);
        this.code = responseCode.getCode();
    }


}
  1. 自定义全局处理器 :GlobalExcaptionHandle
java 复制代码
package cn.varin.hututu.exception;

import cn.varin.hututu.common.BaseResponse;
import cn.varin.hututu.common.ResponseUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
@Slf4j
public class GlobaExceptionHandle {
    /**
     * 自定义异常
     * @param customizeException 自定义异常
     * @return 响应体
     */
    @ExceptionHandler(value = CustomizeException.class)
    public BaseResponse<?> customizeExceptionHandle (CustomizeException customizeException) {
        log.error("CustomizeException>>>>>",customizeException);
        return ResponseUtil.error(customizeException.getCode(), customizeException.getMessage());
    }


    @ExceptionHandler(value = RuntimeException.class)
    public BaseResponse<?> runtimeExceptionHandle (RuntimeException runtimeException) {
        log.error("RuntimeException>>>>>",runtimeException);
        return ResponseUtil.error(ResponseCode.SYSTEM_ERROR.getCode(), ResponseCode.SYSTEM_ERROR.getMessage());
    }


}
  1. 自定义异常捕获工具类:ThrowUtil
java 复制代码
package cn.varin.hututu.exception;

/**
 * 异常工具类
 */
public class ThrowUtil {
    /**
     * 条件成立,抛运行时异常
     * @param flag 条件
     * @param runtimeException 异常
     */
    public static void throwIf(Boolean flag, RuntimeException runtimeException) {
        if (flag) {
            throw runtimeException;
        }
    }

    /**
     * 条件成立,抛异常
     * @param flag 条件
     * @param responseCode 响应码
     */
    public static void throwIf(Boolean flag,ResponseCode responseCode) {
        if (flag) {
            throwIf(flag,new CustomizeException(responseCode));
        }
    }

    /**
     * 条件成立,抛异常
     * @param flag 条件
     * @param code 响应码
     * @param message 响应信息
     */
    public static void throwIf(Boolean flag,Integer code,String message) {
        if (flag) {
            throwIf(flag,new CustomizeException(code,message));
        }
    }


}

5. 自定义后端统一请求响应体

  1. 定义请求响应类:BaseResponse
java 复制代码
package cn.varin.hututu.common;

import cn.varin.hututu.exception.ResponseCode;
import io.swagger.models.auth.In;
import lombok.Data;
import org.apache.catalina.valves.rewrite.RewriteCond;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.io.Serializable;

/**
 * 请求响应体
 */
@Data
public class BaseResponse<T>  implements Serializable {
    private Integer code;
    private String message;
    private T data;
    public BaseResponse(Integer code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }
    public BaseResponse(Integer code, String message) {
        this(code, message, null);
    }
    public BaseResponse(ResponseCode responseCode) {
        this(responseCode.getCode(), responseCode.getMessage(), null);

    }

}
  1. 定义请求响应工具类:ResponseUtil
java 复制代码
package cn.varin.hututu.common;


import cn.varin.hututu.exception.ResponseCode;

public class ResponseUtil {
    /**
     *
     * @param data 数据
     * @return 响应
     * @param <T> 数据类型
     */
    public static<T> BaseResponse<T> success(T data) {
        return  new BaseResponse<>(200, "请求成功", data);
    }

    /**
     *
     * @param responseCode 响应吗枚举
     * @return 响应
     */
    public static BaseResponse<?> error(ResponseCode responseCode) {
        return new BaseResponse<>(responseCode);
    }

    /**
     *
     * @param code 响应码
     * @param message 响应消息
     * @return 响应体
     */
    public static BaseResponse<?> error(Integer code, String message) {
    return new BaseResponse<>(code, message, null);}

    /**
     *
     * @param responseCode 响应枚举
     * @param message 响应消息
     * @return 响应体
     */
    public static BaseResponse<?> error(ResponseCode responseCode, String message) {
        return new BaseResponse<>(responseCode.getCode(), message, null);
    }
}
  1. 定义公共分页请求类:PageRequest
java 复制代码
package cn.varin.hututu.common;

import lombok.Data;

@Data
public class PageRequest {
    // 页号
    private int current = 1;
    // 页数
    private int pageSize = 10;
    // 排序字段
    private String sortField;
    // 降序/升序 默认:降序
    private String sortOrder ="desc";
}
  1. 定义公共删除请求类:DeleteRequest
java 复制代码
package cn.varin.hututu.common;

import lombok.Data;

import java.io.Serializable;

/**
 * 删除请求类
 */
@Data
public class DeleteRequest  implements Serializable {
    private static final long serialVersionUID = 1L;
    private Integer id;
}

6. Mysql连接配置

yaml 复制代码
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://ip:3306/hututu
    username: 你的账号
    password: 你的密码

7. mybatis-plus配置

mybaits-plus配置文档:https://baomidou.com/getting-started/

注意:如果是mybatis升级到mybaitsPlus,需要删除掉原本mybatis 依赖,因为mybaits-plus中包含mybatis。

yaml 复制代码
mybatis-plus:
  configuration:
    # MyBatis 配置
    map-underscore-to-camel-case: false # 下划线转驼峰
    # 如果项目无日志框架,可以考虑指定为 org.apache.ibatis.logging.stdout.StdOutImpl (请勿在实际生产中使用).
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

  global-config:
    db-config:
      logic-delete-field: isDelete # 逻辑删除
      logic-delete-value: true # 为1删除
      logic-not-delete-value: false # 为0不删除

8. 全局跨域配置

java 复制代码
package cn.varin.hututu.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.io.Serializable;

/**
 * 浏览器跨域配置
 */
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {

        registry.addMapping("/**")


                .allowCredentials(true) // 可以发送cookie
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .exposedHeaders("*");
    }
}

9. 接口测试

  1. 创建一个健康检查接口 HealthController
java 复制代码
package cn.varin.hututu.controller;

import cn.varin.hututu.common.BaseResponse;
import cn.varin.hututu.common.ResponseUtil;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/")
public class HealthController {
    /**
     * 项目健康检查
     * @return
     */
    @GetMapping("/health")
    public BaseResponse health() {
        return ResponseUtil.success("success");
    }
}
  1. 访问接口文档页面进行测试

http://localhost:9991/api/doc.htlm

  1. 接口测试结果:

:::success

后端通用模版搭建完成

:::

二、前端框架

1. 依赖版本说明

NPM:v11.6.0

Node:v24.10.0

Vue:v3.12.1

TypeScript:v5.6.3

Ant:v4.2.6

2. 快速构建Vue3+TypeScript前端框架

Vue.js文档说明: https://cn.vuejs.org/guide/quick-start

shell 复制代码
npm create vue@latest # 创建
npm install # 下载依赖
npm run dev # 启动项目

3. 引入组件库 (Ant Design Vue)

官方文档:https://antdv.com/docs/vue/getting-started-cn

本文选择全局安装并注册,只需要局部注册的请自行查询官网文档

  1. 下载依赖
shell 复制代码
npm i --save ant-design-vue@4.x #本文使用版本:4.2.6
  1. 全局注册
    1. 将将以下代码添加到main.ts文件中
typescript 复制代码
import { createApp } from 'vue';
import Antd from 'ant-design-vue';
import App from './App';
import 'ant-design-vue/dist/reset.css';

const app = createApp(App);

app.use(Antd).mount('#app');
  1. 组件测试预览
    1. 到任意页面添加任意Ant组件测试

组件地址:https://antdv.com/components/overview-cn/

图中可以看到日期组件正常使用

vue 复制代码
<a-date-picker />
<a-time-picker />

4. 开发规范

选择遵守VUE3的组合式API开发方式,喜欢选项式API的可以去参考官网文档

plain 复制代码
<!--默认前端模版-->

<template>
  <div id="common-page">

  </div>
</template>

<script setup lang="ts">


</script>

<style scoped>
#common-page {

}
</style>

5. 修改标签页显示信息

修改:

标签页显示表示

标签页显示ico图标

修改文件地址:根目录下的index.html

html 复制代码
<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/public/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>弧图图 ------ 智能图床</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

6. 全局通用布局开发

  1. 开发思路:
    1. 新建一个BasicLayout页面,作为根布局,引入到App.vue文件中。
  2. 实现功能:
    1. 只需要修改App.vue中的布局模版,就可以动态的切换不同的布局文件
  3. 文件位置:
    1. src/layouts/BasicLayout.vue
    2. src/App.vue
vue 复制代码
<template>

    <basic-layout></basic-layout>

</template>
<script lang="ts" setup>

import BasicLayout from '@/layouts/BasicLayout.vue'
  
</script>
vue 复制代码
<!--默认前端模版-->

<template>
  <div id="basic-page">

   
  </div>
</template>

<script setup lang="ts">



</script>

<style scoped>
#basic-page {
  width: 100%;
}

</style>

7. 建立页面上中下布局结构

使用ant 布局组件:https://antdv.com/components/layout-cn

选择需要的布局代码,复制到BasicLayout文件中

本项目选择的页面接收示例:

BasicLayout.vue

vue 复制代码
<!--默认前端模版-->

<template>
  <div id="basic-page">
      <a-layout style="min-width: 100vh">
        <a-layout-header class="headerStyle">
        </a-layout-header>
        <a-layout-content class="contentStyle">
        </a-layout-content>
        <a-layout-footer class="footerStyle">
        
        </a-layout-footer>
      </a-layout>
  </div>
</template>

<script setup lang="ts">

</script>

<style scoped>
  #basic-page {
    width: 100%;
  }

  #basic-page .headerStyle  {
    padding-inline: 0px;
    margin-bottom: 16px;
    color:unset;
    background-color: white;
  }
  #basic-page .contentStyle{
    margin-bottom: 40px;
    padding:20px;
  }

  #basic-page .footerStyle{
    padding:16px;
    background-color: #efefef;
    position: fixed;
    bottom: 0;
    left:0;
    right:0;
    text-align: center;

  }
</style>

8. 建立上中下三层布局的公共内容

上:网站图标、标题,以及路由链接、以及登录按钮等

中:动态切换页面内容

下:展示网站的基本信息,例如:开发者,网站备案情况

  1. basicLayout.vue
vue 复制代码
<!--默认前端模版-->

<template>


  <div id="basic-page">


      <a-layout style="min-width: 100vh">
        <a-layout-header class="headerStyle">

          <global-header></global-header>
        </a-layout-header>
        <a-layout-content class="contentStyle">
          <router-view></router-view>
        </a-layout-content>
        <a-layout-footer class="footerStyle">
          <div style="margin-bottom: 16px;text-align: right">
            <a-radio-group v-model:value="locale">
              <a-radio-button key="en" :value="enUS.locale">English</a-radio-button>
              <a-radio-button key="cn" :value="zhCN.locale">中文</a-radio-button>
            </a-radio-group>
          </div>
          <a href="http:www.varin.cn" target="_blank">
            varin.cn By Varin
          </a>
        </a-layout-footer>
      </a-layout>

  </div>
</template>

<script setup lang="ts">


  import GlobalHeader from '@/components/GlobalHeader.vue'
 

</script>

<style scoped>
  #basic-page {
    width: 100%;
  }

  #basic-page .headerStyle  {
    padding-inline: 0px;
    margin-bottom: 16px;
    color:unset;
    background-color: white;
  }
  #basic-page .contentStyle{
    margin-bottom: 40px;
    padding:20px;
  }

  #basic-page .footerStyle{
    padding:16px;
    background-color: #efefef;
    position: fixed;
    bottom: 0;
    left:0;
    right:0;
    text-align: center;

  }
</style>
  1. 设置路由配置:
typescript 复制代码
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [

    {
      path: '/',
      name: '首页',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/IndexView.vue'),
    },
    {
      path: '/about',
      name: '关于',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/AboutView.vue'),
    }
  ],
})

export default router
  1. 抽离导航栏内容到全局导航栏组件中:

GlobalHeader.vue

vue 复制代码
<template>
  <div id="global-header">

    <a-row>
      <a-col flex="280px">
        <router-link to="/">
          <div class="title-bar">
            <img src="../assets/logo.png" alt="logo" class="logo" />
            <div class="title">弧图图 ------ 智能图床</div>

          </div>
        </router-link>
      </a-col>
      <a-col flex="auto">
        <a-menu v-model:selectedKeys="current" mode="horizontal" :items="items"
          @click="doMenuClick"

          />

      </a-col>
      <a-col flex="200px">
        <div class="user-login-status">

          <div v-if="loginUserStore.loginUser.id">
            {{loginUserStore.loginUser.userName?? "无名"}}
          </div>
          <div v-else>

            <a-button type="primary"  href="/user/login">登录</a-button>

          </div>

        </div>
      </a-col>
    </a-row>




  </div>
</template>
<script lang="ts" setup>
  import { h, ref } from 'vue'
  import { MenuProps } from 'ant-design-vue'
  import {  TagOutlined  } from '@ant-design/icons-vue';


  const loginUserStore = useLoginUserStore()
  loginUserStore.getLoginUser()



  const current = ref<string[]>(['mail'])
    const items = ref<MenuProps['items']>([
      {
        key: '/',
        title: '首页',
        label: '首页',
      },
      {
        key: '/about',
        title: '关于',
        label: '关于',
      },
      {
        key: 'others',
        title: 'BLOG',
        icon: ()=>h(TagOutlined),
        label: h('a', { href: 'https://varin.blog.csdn.net', target: '_blank' }, 'blog'),
      },
    ])

  import {useRouter} from 'vue-router';
  import { useLoginUserStore } from '@/store/userStore'
  const router = useRouter();
  // 路由跳转事件

  const doMenuClick = ({key}:{key:string}) => {
    router.push({
      path:key
    })
  }

  // 解决刷新后菜单高亮失效
  router.afterEach((to) => {
    current.value = [to.path]
  })


</script>
<style scoped>
  #global-header {
    margin:0 30px;
  }

  .title-bar {
    display: flex;
    align-items: center;

    .logo{
      height: 48px;
    }
    .title{
      color: #000;
      font-size: 18px;
      margin-left: 20px;


    }
  }

</style>
  1. 最终效果

9. 集成Axios

官网文档地址:https://axios-http.com/docs/intro

  1. 安装依赖
shell 复制代码
npm install axios
  1. 建立全局自定义请求

参考文档:

基本信息配置:https://axios-http.com/docs/api_intro

拦截器配置:https://axios-http.com/docs/interceptors

typescript 复制代码
import axios from 'axios'
import { message } from 'ant-design-vue'

// Set config defaults when creating the instance


const MyAxios = axios.create({
  baseURL: 'http://localhost:9991/',
  timeout: 60000,
  withCredentials: true, //发送请去时,可以携带cookie
});


// Add a request interceptor 请求拦截
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  }

);

// Add a response interceptor 响应拦截
axios.interceptors.response.use(function onFulfilled(response) {
  // Any status code that lie within the range of 2xx cause this function to trigger
  // Do something with response data

  const {data} = response;
  // 未登录
  if (data.code === 40100) {
    // 后续修改,逻辑:判断是不是登录请求,并且是不是页面,
    if (
     ! response.request.responseUrl.includes('/user/get/login') &&
      !window.location.pathname.includes('/user/login')
    ) {
      message.warning("请登录");
      window.location.href = '/login';
    }

  }
  return response;
}, function onRejected(error) {
  // Any status codes that falls outside the range of 2xx cause this function to trigger
  // Do something with response error
  return Promise.reject(error);
});



export default  MyAxios;

10. 使用OpenAPI实现批量生成前端请求接口文件

OpenAPI TypeScript 生成器介绍文档:https://www.npmjs.com/package/@umijs/openapi

  1. 安装
shell 复制代码
npm i --save-dev @umijs/openapi
  1. 根目录建立openapi.config.ts配置文件
typescript 复制代码
import {generateService} from '@umijs/openapi'



generateService({
  requestLibPath:"import request from '@/request'",  # 使用默认请求文件
  schemaPath:"http://localhost:9991/api/v2/api-docs", # 后端接口地址
  serversPath:"./src" # 生成文件的目录
})
  1. 在 package.json 中添加生成脚本
json 复制代码
"opapi": "node openapi.config.ts "
  1. 运行指令
    1. 注意:运行该指令需要将后端项目启动
  1. 测试请求
    1. 在IndexPage.vue文件中编写任意请求接口代码
vue 复制代码
<template>
  <div id="index-view">
    <h1>
      {{msg}}
    </h1>
<!--    测试组件中英文切换-->
        <a-date-picker />
        <a-time-picker />

  </div>
</template>
<script setup lang="ts">
import { healthUsingGet } from "@/api/healthController";
healthUsingGet().then((res)=>{
  console.log(res);
})

const msg = "弧图图 -- AI智能打造的智能图床"
</script>
<style>

#index-view {

}
</style>

11. 引入全局状态管理Pinia

官网文档:https://pinia.vuejs.org/zh/getting-started.html

  1. 安装依赖
shell 复制代码
npm install pinia
  1. 创建user模块,定义用户信息全局存储、修改、获取功能
typescript 复制代码
import {defineStore} from 'pinia'
import {ref} from 'vue'

export const useLoginUserStore = defineStore("loginUser",()=>{
  // 创建登录用户信息
  const  loginUser = ref<any>({
    userName :"未登录"
  })
  // 获取登录用户
  async  function getLoginUser(){
    // 后端接口没有开发,暂时用定时器模拟
    setTimeout(()=>{
      loginUser.value = {
        id:526,
        userName:"varin"
      }
    },10000)
  }

  // 设置登录用户
  function setLoginUser(newLoginUser: any){
    loginUser.value = newLoginUser

  }

  return { loginUser ,setLoginUser  ,getLoginUser}
});
  1. 使用示例
vue 复制代码
const loginUserStore = useLoginUserStore() # 获取到储存器
loginUserStore.getLoginUser() 获取到登录用户对象

12. 页面国际化设置

ant组件提供的组件可以切换不同的语言,本项目实现了中英文切换

  1. 国际化说明文档:https://antdv.com/docs/vue/i18n-cn
  2. 使用组件:a-config-provider https://antdv.com/components/config-provider-cn
  1. 修改页面:BasicLayout.vue
vue 复制代码
<!--默认前端模版-->

<template>


  <div id="basic-page">

    <a-config-provider :locale="locale === 'en' ? enUS : zhCN">

      <a-layout style="min-width: 100vh">
        <a-layout-header class="headerStyle">

          <global-header></global-header>
        </a-layout-header>
        <a-layout-content class="contentStyle">
          <router-view></router-view>
        </a-layout-content>
        <a-layout-footer class="footerStyle">
          <div style="margin-bottom: 16px;text-align: right">
            <a-radio-group v-model:value="locale">
              <a-radio-button key="en" :value="enUS.locale">English</a-radio-button>
              <a-radio-button key="cn" :value="zhCN.locale">中文</a-radio-button>
            </a-radio-group>
          </div>
          <a href="http:www.varin.cn" target="_blank">
            varin.cn By Varin
          </a>
        </a-layout-footer>
      </a-layout>
    </a-config-provider>

  </div>
</template>

<script setup lang="ts">


  import GlobalHeader from '@/components/GlobalHeader.vue'
  import { ref, watch } from 'vue';
  import enUS from 'ant-design-vue/es/locale/en_US';
  import zhCN from 'ant-design-vue/es/locale/zh_CN';
  import dayjs from 'dayjs';
  import 'dayjs/locale/zh-cn';


  dayjs.locale('en');
  const locale = ref(enUS.locale);
  watch(locale, val => {
    dayjs.locale(val);
  });

</script>

<style scoped>
  #basic-page {
    width: 100%;
  }

  #basic-page .headerStyle  {
    padding-inline: 0px;
    margin-bottom: 16px;
    color:unset;
    background-color: white;
  }
  #basic-page .contentStyle{
    margin-bottom: 40px;
    padding:20px;
  }

  #basic-page .footerStyle{
    padding:16px;
    background-color: #efefef;
    position: fixed;
    bottom: 0;
    left:0;
    right:0;
    text-align: center;

  }
</style>
  1. 预览效果-英文
  1. 预览效果-中文
相关推荐
Fu1co5 小时前
【Spring Boot】Spring Boot解决循环依赖
java·spring boot·spring
我命由我123456 小时前
Derby - Derby 服务器(Derby 概述、Derby 服务器下载与启动、Derby 连接数据库与创建数据表、Derby 数据库操作)
java·运维·服务器·数据库·后端·java-ee·后端框架
技术砖家--Felix6 小时前
Spring Boot入门篇:快速搭建你的第一个Spring Boot应用
java·开发语言·音视频
i源6 小时前
Java语言处理Js文件内容格式化
java·javascript
W.Buffer7 小时前
MyBatis 源码深度解析:从 Spring Boot 实战到底层原理
spring boot·后端·mybatis
普通网友7 小时前
【Spring Boot】Spring Boot解决循环依赖
spring boot·tomcat
为什么要做囚徒8 小时前
IntelliJ IDEA 远程断点调试完全指南
java·ide·intellij-idea
探索宇宙真理.8 小时前
Apache Tomcat RewriteValve目录遍历漏洞 | CVE-2025-55752 复现
java·经验分享·tomcat·apache·安全漏洞