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

简介: 该文档详细介绍弧图图智能图床平台的前后端框架搭建步骤。后端基于 SpringBoot,整合 MybatisPlus、knife4j 等依赖,配置了异常处理、统一响应体等;前端用 Vue3+TypeScript,引入 Ant Design Vue,实现布局、路由、Axios 请求等功能,完成基础框架搭建。

前言:

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

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

核心功能:

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

实现图片存储空间

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

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

一、后端框架

依赖版本说明

SpringBoot版本:2.7.6

JDK:11

MybatisPlus:3.5.14

knife4j:4.4.0

hutool:5.8.38

1. pom.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>

2. knife4j配置

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

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

  1. application.yml
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

3. 自定义异常处理

  1. 定义自定义响应码枚举:ResponseCode
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
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
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
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));
        }
    }
}

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

  1. 定义请求响应类:BaseResponse
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
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
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
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;
}

5. Mysql连接配置

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

6. mybatis-plus配置

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

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

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不删除

7. 全局跨域配置

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("*");
    }
}

8. 接口测试

  1. 创建一个健康检查接口 HealthController
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. 接口测试结果:

后端通用模版搭建完成

二、前端框架

依赖版本说明

NPM:v11.6.0

Node:v24.10.0

Vue:v3.12.1

TypeScript:v5.6.3

Ant:v4.2.6

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

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

npm create vue@latest # 创建
npm install # 下载依赖
npm run dev # 启动项目

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

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

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

  1. 下载依赖
npm i --save ant-design-vue@4.x #本文使用版本:4.2.6
  1. 全局注册
  1. 将将以下代码添加到main.ts文件中
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/

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

<a-date-picker />
<a-time-picker />

3. 开发规范

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

<!--默认前端模版-->
<template>
  <div id="common-page">
  </div>
</template>
<script setup lang="ts">
</script>
<style scoped>
#common-page {
}
</style>

4. 修改标签页显示信息

修改:

标签页显示表示

标签页显示ico图标

修改文件地址:根目录下的index.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>

5. 全局通用布局开发

  1. 开发思路:
  1. 新建一个BasicLayout页面,作为根布局,引入到App.vue文件中。
  1. 实现功能:
  1. 只需要修改App.vue中的布局模版,就可以动态的切换不同的布局文件
  1. 文件位置:
  1. src/layouts/BasicLayout.vue
  2. src/App.vue
<template>
    <basic-layout></basic-layout>
</template>
<script lang="ts" setup>
import BasicLayout from '@/layouts/BasicLayout.vue'
  
</script>
<!--默认前端模版-->
<template>
  <div id="basic-page">
   
  </div>
</template>
<script setup lang="ts">
</script>
<style scoped>
#basic-page {
  width: 100%;
}
</style>

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

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

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

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

BasicLayout.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>

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

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

中:动态切换页面内容

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

  1. basicLayout.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. 设置路由配置:
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

<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. 最终效果

8. 集成Axios

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

  1. 安装依赖
npm install axios
  1. 建立全局自定义请求

参考文档:

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

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

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;

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

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

  1. 安装
npm i --save-dev @umijs/openapi
  1. 根目录建立openapi.config.ts配置文件
import {generateService} from '@umijs/openapi'
generateService({
  requestLibPath:"import request from '@/request'",  # 使用默认请求文件
  schemaPath:"http://localhost:9991/api/v2/api-docs", # 后端接口地址
  serversPath:"./src" # 生成文件的目录
})
  1. 在 package.json 中添加生成脚本
"opapi": "node openapi.config.ts "

  1. 运行指令
  1. 注意:运行该指令需要将后端项目启动

  1. 测试请求
  1. 在IndexPage.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>

10. 引入全局状态管理Pinia

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

  1. 安装依赖
npm install pinia
  1. 创建user模块,定义用户信息全局存储、修改、获取功能
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. 使用示例
const loginUserStore = useLoginUserStore() # 获取到储存器
loginUserStore.getLoginUser() 获取到登录用户对象

11. 页面国际化设置

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

  1. 国际化说明文档:https://antdv.com/docs/vue/i18n-cn
  2. 使用组件:a-config-provider  https://antdv.com/components/config-provider-cn
  3. 修改页面:BasicLayout.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. 预览效果-中文

目录
相关文章
|
7月前
|
传感器 人工智能 IDE
AI IDE正式上线!通义灵码开箱即用
作为AI原生的开发环境工具,通义灵码AI IDE深度适配了最新的千问3大模型,并全面集成通义灵码插件能力,具备编程智能体、行间建议预测、行间会话等功能。
2744 16
|
3月前
|
人工智能 Java API
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
本文介绍AI大模型的核心概念、分类及开发者学习路径,重点讲解如何选择与接入大模型。项目基于Spring Boot,使用阿里云灵积模型(Qwen-Plus),对比SDK、HTTP、Spring AI和LangChain4j四种接入方式,助力开发者高效构建AI应用。
1546 122
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
|
5月前
|
IDE 前端开发 开发工具
用通义灵码喝鸡汤,天天正能量!
本文介绍了如何使用通义灵码快速生成一个带有翻页动效的“每日一句”组件。通过简洁指令,实现鸡汤语录展示、左右切换与动画效果,适合首页横幅使用。后续还优化了UI布局、增加全屏播放和呼吸动画,使页面更生动美观,极大提升用户体验。
|
3月前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段三:自定义 Advisor 与结构化输出实现以及对话记忆持久化开发
本文介绍如何在Spring AI中自定义Advisor实现日志记录、结构化输出、对话记忆持久化及多模态开发,结合阿里云灵积模型Qwen-Plus,提升AI应用的可维护性与功能性。
681 125
AI 超级智能体全栈项目阶段三:自定义 Advisor 与结构化输出实现以及对话记忆持久化开发
|
2月前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段四:学术分析 AI 项目 RAG 落地指南:基于 Spring AI 的本地与阿里云知识库实践
本文介绍RAG(检索增强生成)技术,结合Spring AI与本地及云知识库实现学术分析AI应用,利用阿里云Qwen-Plus模型提升回答准确性与可信度。
1037 90
AI 超级智能体全栈项目阶段四:学术分析 AI 项目 RAG 落地指南:基于 Spring AI 的本地与阿里云知识库实践
|
3月前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
本文讲解 Prompt 基本概念与 10 个优化技巧,结合学术分析 AI 应用的需求分析、设计方案,介绍 Spring AI 中 ChatClient 及 Advisors 的使用。
1321 133
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
|
NoSQL Java Redis
请勿过度依赖Redis的过期监听
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! Redis过期监听场景 业务中有类似等待一定时间之后执行某种行为的需求 , 比如30分钟之后关闭订单 . 网上有很多使用Redis过期监听的Demo , 但是其实这是个大坑 , 因为Redis不能确保key在指定时间被删除 , 也就造成了通知的延期。
请勿过度依赖Redis的过期监听
|
2月前
|
人工智能 API 开发工具
构建AI智能体:一、初识AI大模型与API调用
本文介绍大模型基础知识及API调用方法,涵盖阿里云百炼平台密钥申请、DashScope SDK使用、Python调用示例(如文本情感分析、图像文字识别),助力开发者快速上手大模型应用开发。
1171 16
构建AI智能体:一、初识AI大模型与API调用
|
1月前
|
开发框架 JavaScript .NET
ASP.NET Core Blazor简介和快速入门二(组件基础)
大家好,我是码农刚子。上一章介绍了Blazor的简介,开发工具及环境,基本语法和一些示例。接下来我们继续了解Blazor 组件相关的基础知识,希望对你有所帮助。
154 6
ASP.NET Core Blazor简介和快速入门二(组件基础)
|
1月前
|
Web App开发 存储 人工智能
Web-Dev-For-Beginners:微软开源的 Web 开发课程,值得花 3 个月认真学
微软开源的 Web 开发课程,12 周讲解 HTML/CSS/JavaScript。通过 6 个实战项目(植物园、打字游戏、浏览器扩展、太空游戏、银行应用、代码编辑器)掌握前端技能。配套 48 个测验,适合零基础,学完产出完整作品集。

热门文章

最新文章