当前位置: 首页 > news >正文

使用 Vue3 + Pinia + Ant Design Vue3 搭建后台管理系统

Vue3 & Ant Design Vue3基础


nodejs版本要求:node-v18.16.0-x64
nodejs基础配置

npm -v
node -vnpm config set prefix "D:\software\nodejs\node_global"
npm config set cache "D:\software\nodejs\node_cache"npm config get registry
npm config set registry https://registry.npm.taobao.org

安装Vue3

npm install @vue/cli -g
vue --version#npm install @vue/cli@5.0.8 -g	安装指定版本
#npm uninstall @vue/cli -g

使用Vue创建前端项目

npm create vue@latest
√ Project name: ...web
√ Add TypeScript? ... No 
√ Add JSX Support? ... No 
√ Add Vue Router for Single Page Application development? ...  Yes
√ Add Pinia for state management? ...  Yes
√ Add Vitest for Unit Testing? ... No 
√ Add an End-to-End Testing Solution? » No
√ Add ESLint for code quality? ... Yes
√ Add Prettier for code formatting? ... Yes

启动前端项目

cd web
npm install
npm run dev

浏览器访问:http://localhost:5173
修改端口号,修改配置 vite.config.js

export default defineConfig({server: {port: 9000},plugins: [vue(),],resolve: {alias: {'@': fileURLToPath(new URL('./src', import.meta.url))}}
})

再次访问:http://localhost:9000/


https://antdv.com/components/overview-cn
Ant Design Vue官方文档

安装Ant Design Vue

npm install ant-design-vue --save
npm install --save @ant-design/icons-vue#自动按需引入组件
npm install unplugin-vue-components -D

修改配置文件vite.config.js

import {fileURLToPath, URL} from 'node:url'import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite';
import {AntDesignVueResolver} from 'unplugin-vue-components/resolvers';// https://vitejs.dev/config/
export default defineConfig({server: {port: 9000},plugins: [vue(),Components({resolvers: [AntDesignVueResolver({importStyle: false, // css in js}),],}),],resolve: {alias: {'@': fileURLToPath(new URL('./src', import.meta.url))}}
})

修改main.js

import './assets/main.css'import { createApp } from 'vue'
import { createPinia } from 'pinia'
import Antd from 'ant-design-vue';import App from './App.vue'
import router from './router'
import 'ant-design-vue/dist/reset.css';const app = createApp(App)app.use(createPinia())
app.use(router)
app.use(Antd)app.mount('#app')

添加一个测试页面

<script setup>
import {ZoomOutOutlined} from "@ant-design/icons-vue";
</script><template><div class="about"><h1>This is an about page</h1><a-button>测试</a-button><br><ZoomOutOutlined /></div>
</template><style>
</style>

Antd栅格把页面平均分成24份

<template><a-row><a-col :span="24">col</a-col></a-row><a-row><a-col :span="12">col-12</a-col><a-col :span="12">col-12</a-col></a-row><a-row><a-col :span="8">col-8</a-col><a-col :span="8">col-8</a-col><a-col :span="8">col-8</a-col></a-row><a-row><a-col :span="6">col-6</a-col><a-col :span="6">col-6</a-col><a-col :span="6">col-6</a-col><a-col :span="6">col-6</a-col></a-row>
</template>

使用Pinia管理用户状态

刷新页面,Pinia中的数据会丢失,使用Pinia插件做数据持久化

npm install --save zipson
npm install --save pinia-plugin-persistedstate

修改main.js

import './assets/main.css'import { createApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import Antd from 'ant-design-vue';import App from './App.vue'
import router from './router'
import 'ant-design-vue/dist/reset.css';const app = createApp(App)
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate);//pinia数据持久化app.use(pinia)
app.use(router)
app.use(Antd)app.mount('#app')

使用Pinia保存用户状态,添加文件src/stores/user.js

import {reactive} from 'vue'
import {defineStore} from 'pinia'
import {stringify, parse} from 'zipson'const MEMBER = "MEMBER"
export const useUserStore = defineStore('user', () => {const userInfo = reactive({id: '',mobile: '',token: ''})function setUserInfo({id, mobile, token}) {userInfo.id = iduserInfo.mobile = mobileuserInfo.token = token}function clearUserInfo() {userInfo.id = ''userInfo.mobile = ''userInfo.token = ''}return {userInfo, setUserInfo, clearUserInfo}
}, {persist: {key: MEMBER,storage: sessionStorage,// paths: ['count'],serializer: {deserialize: parse,serialize: stringify},beforeRestore: (ctx) => {console.log(`about to restore '${ctx.store.$id}'`)},afterRestore: (ctx) => {console.log(`just restored '${ctx.store.$id}'`)},debug: true,}
})

ite多环境配置

https://vitejs.cn/vite3-cn/guide/env-and-mode.html#env-variables
官方配置文档

在根目录创建文件 .env.development

NODE_ENV=development
#自定义变量需要以VITE_开头
VITE_APP_BASE_URL=http://localhost:8000

生产环境 .env.production

NODE_ENV=production
VITE_APP_BASE_URL=http://train.intmall.com

使用环境变量

axios.defaults.baseURL = import.meta.env.VITE_APP_BASE_URL;
console.log(process.env.NODE_ENV)
console.log(import.meta.env.VITE_APP_BASE_URL)

封装网络请求工具类Axios

npm install axios --save

封装网络请求工具类 src/utils/request.js

import axios from 'axios'
import {notification} from 'ant-design-vue';
import {useUserStore} from '@/stores/user';
import router from '@/router'const {userInfo, clearUserInfo} = useUserStore()
export const serverUrl = import.meta.env.VITE_APP_BASE_URLconst service = axios.create({baseURL: serverUrl,timeout: 5000
})// Add a request interceptor 全局请求拦截
service.interceptors.request.use(function (config) {// Do something before request is sentconst token = userInfo.tokenif (token) {config.headers['token'] = token}// 此处还可以设置tokenreturn config},function (error) {// Do something with request errorreturn Promise.reject(error)}
)// Add a response interceptor 全局相应拦截
service.interceptors.response.use(function (response) {// Any status code that lie within the range of 2xx cause this function to trigger// Do something with response data// 如果是固定的数据返回模式,此处可以做继续完整的封装const resData = response.data || {}if (resData.success) {return resData}notification.error({description: resData.message});return Promise.reject(resData.message)},function (error) {// Any status codes that falls outside the range of 2xx cause this function to trigger// Do something with response error// 此处需要对返回的状态码或者异常信息作统一处理console.log('error', error)const response = error.response;const status = response.status;if (status === 401) {// 判断状态码是401 跳转到登录页console.log("未登录或登录超时,跳到登录页");clearUserInfo()notification.error({description: "未登录或登录超时"});router.push('/login')}return Promise.reject(error)}
)export const get = (url, params) => {return service.get(url, {params})
}export const post = (url, data) => service.post(url, data)export const put = (url, data) => service.put(url, data)export const del = (url, data) => service.delete(url)

遇到的问题:
useRouter失效,router无法跳转页面
https://blog.csdn.net/qq_57700056/article/details/133530562

后台接口调用示例: src/api/userApi.js

import { get, post, put, del } from "../utils/request";// 用户登录
export async function login(data) {return post('/member/member/login', data)
}export async function sendCode(data) {return post('/member/member/sendCode', data)
}export async function getUserCount() {return get('/member/member/count')
}export async function savePassenger(data) {return post('/member/passenger/save', data)
}export async function queryPassengerList(data) {return post('/member/passenger/queryList', data)
}export async function deletePassenger(id) {return del(`/member/passenger/delete/${id}`)
}// 导出 userApi 方法
export default {login,sendCode,getUserCount,savePassenger,deletePassenger,queryPassengerList
}

前端页面路由配置

增加路由防卫,判断要跳转的页面是否需要登录
src/router/index.js
由于router挂载比pinia要早,守卫在在使用pinia时,pinia还没有挂载,把pinia写在守卫里面即可解决问题

import {createRouter, createWebHistory} from 'vue-router'
import {notification} from 'ant-design-vue';
import {useUserStore} from '@/stores/user';const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: '/',name: 'main',component: () => import('../views/MainView.vue'),children: [{path: '/welcome',name: 'welcome',component: () => import('../views/main/WelcomeView.vue')}, {path: '/passenger',name: 'passenger',component: () => import('../views/main/PassengerView.vue')}]},{path: '/login',name: 'login',component: () => import('../views/LoginView.vue'),meta: {noToken: true}}, {path: '',redirect: '/welcome'}]
})// 路由登录拦截
router.beforeEach((to, from, next) => {// 要不要对meta.noToken属性做监控拦截if (to.matched.some(function (item) {console.log(item, "是否不需要登录校验:", item.meta.noToken || false);return !item.meta.noToken})) {const {userInfo} = useUserStore()console.log("页面登录校验开始:", userInfo);if (!userInfo.token) {console.log("用户未登录或登录超时!");notification.error({description: "未登录或登录超时"});next('/login');} else {next();}} else {next();}
});export default router

登录页面

<script setup>
import {reactive} from 'vue';
import {useRouter} from 'vue-router'
import {CodepenCircleOutlined} from "@ant-design/icons-vue";
import {notification} from 'ant-design-vue';
import userApi from '../api/userApi';
import { useUserStore } from '@/stores/user';
const { setUserInfo } = useUserStore()const router = useRouter();const loginForm = reactive({mobile: '',code: '',
});
const onFinish = async (value) => {// 执行登录逻辑const respData = await userApi.login(value);const data = respData.datasetUserInfo(data)console.log('Success:', value, data);notification.success({ description: '登录成功!' });router.push("/welcome");
};
const onFinishFailed = errorInfo => {console.log('Failed:', errorInfo);
};const sendCode = async () => {await userApi.sendCode({mobile: loginForm.mobile})notification.success({ description: '发送验证码成功!' });loginForm.code = "8888";
}
</script><template><a-row class="login"><a-col :span="8" :offset="8" class="login-main"><h1 style="text-align: center"><CodepenCircleOutlined/>&nbsp;模拟12306售票系统</h1><a-form:model="loginForm"name="basic"autocomplete="off"@finish="onFinish"@finishFailed="onFinishFailed"><a-form-itemlabel=""name="mobile":rules="[{ required: true, message: '请输入手机号!' }]"><a-input v-model:value="loginForm.mobile" placeholder="手机号"/></a-form-item><a-form-itemlabel=""name="code":rules="[{ required: true, message: '请输入验证码!' }]"><a-input v-model:value="loginForm.code"><template #addonAfter><a @click="sendCode">获取验证码</a></template></a-input></a-form-item><a-form-item :wrapper-col="{ offset: 8, span: 16 }"><a-button type="primary" html-type="submit">登录</a-button></a-form-item></a-form></a-col></a-row></template><style scoped>
.login-main h1 {font-size: 25px;font-weight: bold;
}.login-main {margin-top: 100px;padding: 30px 30px 20px;border: 2px solid grey;border-radius: 10px;background-color: #fcfcfc;
}
</style>

退出登录

<script setup>
import {ref} from "vue";
import {useUserStore} from '@/stores/user';const {userInfo, clearUserInfo} = useUserStore()const selectedKeys1 = ref(['2']);
</script><template><a-layout-header class="header"><div class="logo"/><div style="float: right; color: white;">您好:{{userInfo.mobile}} &nbsp;&nbsp;<router-link to="/login" @click.native="clearUserInfo()" style="color: white;">退出登录</router-link></div><a-menuv-model:selectedKeys="selectedKeys1"theme="dark"mode="horizontal":style="{ lineHeight: '64px' }"><a-menu-item key="1">nav 1</a-menu-item><a-menu-item key="2">nav 2</a-menu-item><a-menu-item key="3">nav 3abc</a-menu-item></a-menu></a-layout-header>
</template>

页面增删改查操作

<script setup>
import {ref, reactive} from 'vue';
import {notification} from "ant-design-vue";
import {cloneDeep} from 'lodash-es';
import userApi from '@/api/userApi';
import {PASSENGER_TYPE_ARRAY} from '@/assets/js/enums'const visible = ref(false);
const loading = ref(false);let passenger = ref({id: undefined,memberId: undefined,name: undefined,idCard: undefined,type: undefined,createTime: undefined,updateTime: undefined,
});const passengers = ref([]);
const pagination = reactive({total: 0,current: 1,pageSize: 2
})const columns = [{title: '姓名',dataIndex: 'name',key: 'name',},{title: '身份证',dataIndex: 'idCard',key: 'idCard',},{title: '旅客类型',dataIndex: 'type',key: 'type',},{title: '操作',dataIndex: 'operation'},
]
const handleQuery = (param) => {if (!param) {param = {"page": 1,"size": pagination.pageSize}}loading.value = true;userApi.queryPassengerList({"page": param.page,"limit": param.size}).then(res => {console.log('res', res)loading.value = false;passengers.value = res.data;pagination.total = res.count;pagination.current = res.page})
}const handleTableChange = (pagination) => {handleQuery({page: pagination.current,size: pagination.pageSize})
}handleQuery()const onAdd = () => {passenger.value = {};visible.value = true;
}const onEdit = (record) => {console.log("record", record)passenger.value = cloneDeep(record);visible.value = true;
}const onDelete = (record) => {console.log("delete record", record)userApi.deletePassenger(record.id).then(() => {notification.success({description: "删除成功!"});handleQuery({page: pagination.current,size: pagination.pageSize,});})
}const handleOk = () => {userApi.savePassenger(passenger.value).then(resp => {notification.success({description: "保存成功!"});visible.value = false;handleQuery({page: pagination.current,size: pagination.pageSize})})
}
</script><template><p><a-space><a-button type="primary" @click="handleQuery()">刷新</a-button><a-button type="primary" @click="onAdd">新增</a-button></a-space></p><a-table :dataSource="passengers" :columns="columns" :pagination="pagination" @change="handleTableChange":loading="loading"><template #bodyCell="{ column, text, record }"><template v-if="column.dataIndex === 'operation'"><a-space><a @click="onEdit(record)">编辑</a><a-popconfirmtitle="删除后不可恢复,确认删除?"ok-text="确认" cancel-text="取消"@confirm="onDelete(record)"><a style="color: red">删除</a></a-popconfirm></a-space></template><template v-else-if="column.dataIndex === 'type'"><span v-for="item in PASSENGER_TYPE_ARRAY" :key="item.code"><span v-if="item.code === record.type">{{item.desc}}</span></span></template></template></a-table><a-modal v-model:open="visible" title="乘车人" @ok="handleOk"ok-text="确认" cancel-text="取消"><a-form:model="passenger" :label-col="{span: 4}" :wrapper-col="{ span: 20 }"><a-form-item label="姓名"><a-input v-model:value="passenger.name"/></a-form-item><a-form-item label="身份证"><a-input v-model:value="passenger.idCard"/></a-form-item><a-form-item label="旅客类型"><a-select v-model:value="passenger.type"><a-select-option v-for="item in PASSENGER_TYPE_ARRAY" :key="item.code" :value="item.code">{{ item.desc }}</a-select-option></a-select></a-form-item></a-form></a-modal></template>

前端跨域问题

前后端分离项目,前端在请求后台接口时会出现跨域问题
这个后端项目使用到了gateway,在配置文件中加入:

# 允许请求来源(老版本叫allowedOrigin)
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowedOriginPatterns=*
# 允许携带的头信息
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowedHeaders=*
# 允许的请求方式
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowedMethods=*
# 是否允许携带cookie
spring.cloud.gateway.globalcors.cors-configurations.[/**].allowCredentials=true
# 跨域检测的有效期,会发起一个OPTION请求
spring.cloud.gateway.globalcors.cors-configurations.[/**].maxAge=3600

后端分页查询方法

#CommonPageParam.java
@Data
public class CommonPageParam {@NotNull(message = "页码不能为空")private Integer page;@NotNull(message = "每页数量不能为空")@Max(value = 100, message = "分页条数不能超过100")private Integer limit;
}#PassengerQueryReq.java
@Data
public class PassengerQueryReq extends CommonPageParam {private Long memberId;
}#CommonPageResp.java
@Data
@NoArgsConstructor
public class CommonPageResp<T> {/** 默认每页的条数 */public static final int PAGE_SIZE_DEFAULT = 10;/*** 业务上的成功或失败*/private boolean success = true;/*** 返回信息*/private String message;/*** 返回泛型数据,自定义类型*/private List<T> data;/*** 总数*/private Long count;/*** 页码*/private Integer page;/*** 每页数量*/private Integer limit;public Integer getPage() {if (page == null || page < 1) {return 1;}return page;}public Integer getLimit() {if (limit == null) {return PAGE_SIZE_DEFAULT;}return limit;}public static <T> CommonPageResp<T> SUCCESS(String message, List<T> data, PageInfo pageInfo) {return new CommonPageResp<>(true, message, data, pageInfo.getTotal(), pageInfo.getPageNum(), pageInfo.getPageSize());}public CommonPageResp(boolean success, String message, List<T> data, Long count, Integer page, Integer limit) {this.success = success;this.message = message;this.data = data;this.count = count;this.page = page;this.limit = limit;}
}#PassengerService.java
@Service
@Slf4j
public class PassengerService {@Resourceprivate PassengerMapper passengerMapper;public CommonPageResp<PassengerQueryResp> queryList(PassengerQueryReq req) {PassengerExample passengerExample = new PassengerExample();passengerExample.setOrderByClause("id desc");PassengerExample.Criteria criteria = passengerExample.createCriteria();if (ObjectUtil.isNotNull(req.getMemberId())) {criteria.andMemberIdEqualTo(req.getMemberId());}PageHelper.startPage(req.getPage(), req.getLimit());List<Passenger> passengerList = passengerMapper.selectByExample(passengerExample);PageInfo<Passenger> pageInfo = new PageInfo<>(passengerList);List<PassengerQueryResp> list = BeanUtil.copyToList(passengerList, PassengerQueryResp.class);return CommonPageResp.SUCCESS("", list, pageInfo);}
}

使用线程本地变量存储用户信息

拦截器从token中获取用户信息

@Slf4j
@Component
public class MemberInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("MemberInterceptor开始");//获取header的token参数String token = request.getHeader("token");if (StrUtil.isNotBlank(token)) {log.info("获取会员登录token:{}", token);JSONObject loginMember = JwtUtil.getJSONObject(token);log.info("当前登录会员:{}", loginMember);MemberLoginResp member = JSONUtil.toBean(loginMember, MemberLoginResp.class);LoginMemberContext.setMember(member);}log.info("MemberInterceptor结束");return true;}
}

配置开启拦截器

@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {@Resourceprivate MemberInterceptor memberInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 路径不要包含context-pathregistry.addInterceptor(memberInterceptor).addPathPatterns("/**").excludePathPatterns("/hello","/member/sendCode","/member/login");}
}

设置用户到本地线程

import com.intmall.train.common.domain.resp.MemberLoginResp;
import lombok.extern.slf4j.Slf4j;@Slf4j
public class LoginMemberContext {private static ThreadLocal<MemberLoginResp> member = new ThreadLocal<>();public static MemberLoginResp getMember() {return member.get();}public static void setMember(MemberLoginResp member) {LoginMemberContext.member.set(member);}public static Long getId() {try {return member.get().getId();} catch (Exception e) {log.error("获取登录会员信息异常", e);throw e;}}
}

源码地址

完整代码参考:
https://gitee.com/galen.zhang/train

相关文章:

使用 Vue3 + Pinia + Ant Design Vue3 搭建后台管理系统

Vue3 & Ant Design Vue3基础 nodejs版本要求&#xff1a;node-v18.16.0-x64 nodejs基础配置 npm -v node -vnpm config set prefix "D:\software\nodejs\node_global" npm config set cache "D:\software\nodejs\node_cache"npm config get registry …...

SpringCloud核心组件

Eureka 注册中心&#xff0c;服务的注册与发现 Feign远程调用 Ribbon负载均衡&#xff0c;默认轮询 Hystrix 熔断 降级 Zuul微服务网关&#xff08;这个组件负责网络路由&#xff0c;可以做统一的降级、限流、认证授权、安全&#xff09; Eureka 微服务的功能主要有以下几…...

基于C++11实现将IP地址、端口号和连接状态写入文件

要基于C11实现将IP地址、端口号和连接状态写入文件&#xff0c;您可以使用std::ofstream类来打开文件并进行写入操作。以下是一个示例&#xff1a; #include <iostream> #include <fstream>void writeConnectionStatus(const std::string& ip, int port, bool…...

非空断言,

先看下TypeScript基础之非空断言操作符、可选链运算符、空值合并运算符-CSDN博客 我没有复现出来&#xff0c;但是我知道了它的作用 用 let str: string arg!; 代替 let str: string; if (arg) { str arg; } 非空断言&#xff08;!&#xff09;和不使用的区别在于对于…...

Spark---创建DataFrame的方式

1、读取json格式的文件创建DataFrame 注意&#xff1a; 1、可以两种方式读取json格式的文件。 2、df.show()默认显示前20行数据。 3、DataFrame原生API可以操作DataFrame。 4、注册成临时表时&#xff0c;表中的列默认按ascii顺序显示列。 df.createTempView("mytab…...

瑜伽学习零基础入门,各种瑜伽教学方法全集

一、教程描述 练习瑜伽的好处多多&#xff0c;能够保证平衡健康的身体基础&#xff0c;提升气质、塑造形体、陶冶情操&#xff0c;等等。本套教程是瑜伽的组合教程&#xff0c;共由33套视频教程组合而成&#xff0c;包含了塑身纤体&#xff0c;速效瘦身&#xff0c;四季养生&a…...

pycharm编译报错处理

1.c生成工具下载 https://visualstudio.microsoft.com/visual-cpp-build-tools/ 在这里插入图片描述 pip install pycocotools...

“华为杯”研究生数学建模竞赛2019年-【华为杯】E题:基于多变量的全球气候与极端天气模型的构建与应用(附python代码实现)

目录 摘 要: 一.问题重述 1.1 问题背景 1.2 问题提出 二.模型假设及符号设定...

冒泡排序(适合编程新手的体质)

冒泡排序&#xff1a;简单而高效的排序技巧 欢迎来到我们今天的博客&#xff0c;我们将一起探索计算机科学中最基本但同时也非常重要的概念之一&#xff1a;冒泡排序。无论你是编程新手还是有一些编程经验的读者&#xff0c;这篇博客都将帮助你更好地理解冒泡排序的原理和应用…...

pdfjs,pdf懒加载

PDF.js是一个使用JavaScript实现的PDF阅读器&#xff0c;它可以在Web浏览器中显示PDF文档。PDF.js支持懒加载&#xff0c;也就是说&#xff0c;它可以在用户滚动页面时才加载PDF文档的某些部分&#xff0c;从而减少初始加载时间和内存占用。 注意点&#xff1a;如果要运行在多留…...

K8s 多租户方案的挑战与价值

在当今企业环境中&#xff0c;随着业务的快速增长和多样化&#xff0c;服务器和云资源的管理会越来越让人头疼。K8s 虽然很强大&#xff0c;但在处理多个部门或团队的业务部署需求时&#xff0c;如果缺乏有效的多租户支持&#xff0c;在效率和资源管理方面都会不尽如人意。 本…...

单链表相关经典算法OJ题:移除链表元素

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 题目&#xff1a;移除链表元素 解法一&#xff1a; 解法一的代码实现&#xff1a; 解法二&#xff1a; 解法二代码的实现&#xff1a; 总结 前言 世上有两种耀眼的…...

【JUC】十九、volatile与内存屏障

文章目录 1、volatile的两大特性2、volatile的四大内存屏障3、分类4、happens-before之volatile变量重排规则5、读写屏障插入策略 1、volatile的两大特性 被volatile修饰的变量有两大特点&#xff1a; 可见性有序性 关于volatile的可见性&#xff0c;也即volatile的内存语义…...

下载MySQL JDBC驱动的方法

说明 java代码通过JDBC访问MySQL数据库&#xff0c;需要MySQL JDBC驱动。 例如&#xff0c;下面这段代码&#xff0c;因为找不到JDBC驱动&#xff0c;所以执行会报异常&#xff1a; package com.thb;public class JDBCDemo {public static void main(String[] args) throws …...

C/C++ 实现FTP文件上传下载

FTP&#xff08;文件传输协议&#xff09;是一种用于在网络上传输文件的标准协议。它属于因特网标准化的协议族之一&#xff0c;为文件的上传、下载和文件管理提供了一种标准化的方法&#xff0c;在Windows系统中操作FTP上传下载可以使用WinINet库&#xff0c;WinINet&#xff…...

第十三章 python之爬虫

Python基础、函数、模块、面向对象、网络和并发编程、数据库和缓存、 前端、django、Flask、tornado、api、git、爬虫、算法和数据结构、Linux、设计题、客观题、其他 第十三章 爬虫 1. 写出在网络爬取过程中, 遇到防爬问题的解决办法。 在网络爬取过程中&#xff0c;可能会遇…...

scrum 敏捷开发

scrum 敏捷开发 Scrum 是一种敏捷软件开发方法&#xff0c;旨在通过迭代、增量和协作的方式提高团队的效率和产品质量。下面是关于 Scrum 的一些重要概念和实践&#xff1a; 1. Scrum 团队角色 Scrum 团队通常由以下角色组成&#xff1a; 产品负责人&#xff08;Product Ow…...

亚信科技AntDB数据库完成中国信通院数据库迁移工具专项测试

近日&#xff0c;在中国信通院“可信数据库”数据库迁移工具专项测试中&#xff0c;湖南亚信安慧科技有限公司&#xff08;简称&#xff1a;亚信安慧科技&#xff09;数据库数据同步平台V2.1产品依据《数据库迁移工具能力要求》、结合亚信科技AntDB分布式关系型数据库产品&…...

深度学习(一):Pytorch之YOLOv8目标检测

1.YOLOv8 2.模型详解 2.1模型结构设计 和YOLOv5对比&#xff1a; 主要的模块&#xff1a; ConvSPPFBottleneckConcatUpsampleC2f Backbone ----->Neck------>head Backdone 1.第一个卷积层的 kernel 从 6x6 变成了 3x3 2. 所有的 C3 模块换成 C2f&#xff0c;可以发现…...

EasyExcel如何读取全部Sheet页数据方法

一、需求描述 Excel表格里面大约有20个sheet页&#xff0c;每个sheet页65535条数据&#xff0c;需要读取全部数据&#xff0c;并导入至数据库。 找了好多种方式&#xff0c;EasyExcel比较符合&#xff0c;下面看代码。 二、实现方式 采用EasyExcel框架的doReadAll()方法 1、…...

GDPU 数据结构 天码行空12

文章目录 数据结构实验十二 图的遍历及应用一、【实验目的】二、【实验内容】三、实验源代码&#x1f37b; CPP&#x1f37b; C 数据结构实验十二 图的遍历及应用 一、【实验目的】 1、 理解图的存储结构与基本操作&#xff1b; 2、熟悉图的深度度优先遍历和广度优先遍历算法…...

什么是 Proxy?

目录 Proxy 的作用 1. 流量过滤 2. 记录日志 3. 加快访问速度 4. 隐藏 IP 地址 Proxy 的分类 1. 按协议分类 - HTTP 代理&#xff1a;只支持 HTTP 协议的代理服务器&#xff0c;它可以缓存 HTTP 请求和响应并过滤 HTTP 流量。 - FTP 代理&#xff1a;只支持 FTP 协议的…...

Vue系列:Vue Element UI中,使用按钮实现视频的播放、停止、停止后继续播放、播放完成后重新播放功能

最近在工作中有个政务大屏用到了视频播放&#xff1b; 技术栈是Vue2、Element UI&#xff1b; 要实现的功能是&#xff1a;使用按钮实现视频的播放、停止、停止后继续播放、播放完成后重新播放功能 具体可以按照以下步骤进行操作&#xff1a; 引入插件&#xff1a; 在Vue组件…...

.Net 8 Blazor下 Auto交互渲染模式试用

一、环境 C:\Users\zhuji>dotnet --version 8.0.100C:\Users\zhuji>dotnet --list-sdks 5.0.403 [C:\Program Files\dotnet\sdk] 6.0.404 [C:\Program Files\dotnet\sdk] 8.0.100 [C:\Program Files\dotnet\sdk] Microsoft Visual Studio Enterprise 2022 (64 位) - Cu…...

AndroidStudio - 新版本 Logcat 使用详解

最近这俩天正好有时间给自己做一下减法&#xff0c;忘记是去年还是今年&#xff0c;在升级 AndroidStudio 后使用 Logcat查看日志的方式也发生了一些变化&#xff0c;虽然一直在使用&#xff0c;但每当看到之前还未关闭 Logcat 命令行工具额昂也&#xff0c;就感觉可能还存在知…...

Webpack ECMAScript 模块

文章目录 前言标题一导出导入将模块标记为 ESM 后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;webpack &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&a…...

knife4j集合化postman

knife4j集合化postman 01 knife4j的介绍 基于 JavaMVC的集成框架swagger的进一步强化&#xff0c;在原有通过注释就能生成文档的前身swagger-bootstrap-ui之上&#xff0c;增加了postman的测试功能&#xff0c;优化了文档的UI界面&#xff0c;在测试api接口的方面有了极大的进…...

MongoDB的原子性和多文档事务处理

原子性和事务处理是数据库操作的核心&#xff0c;保证了数据的准确性。依据数据库原子性&#xff0c;数据库和使用数据库的人员定义事务处理的方式。本文依据Mongodb的官方文档&#xff0c;整理Mongodb数据库的原子性和事务处理方法。 Mongodb的原子操作 Mongodb中&#xff0c…...

代理模式 1、静态代理 2、动态代理 jdk自带动态代理 3、Cglib代理

文章目录 代理模式1、静态代理2、动态代理jdk自带动态代理 3、Cglib代理 来和大家聊聊代理模式 代理模式 代理模式&#xff1a;即通过代理对象访问目标对象&#xff0c;实现目标对象的方法。这样做的好处是&#xff1a;可以在目标对象实现的基础上&#xff0c;增强额外的功能操…...

ELK+filebeat+kafka

无需创建logstash的端口&#xff0c;直接创建topic 远程收集mysql和httpd的日志 &#xff08;一&#xff09;安装nginx和mysql服务 1、打开mysql的日志功能 2、创建日志&#xff08;创库、创表、添加数据&#xff09; &#xff08;1&#xff09;mysql服务器上安装http system…...