目前因学业任务比较重,没有好好的完善,现在比较完善的只有题库管理,新增题库,修改题库以及登录的功能,但搭配小程序使用,主体功能已经实现了
此后台系统是为了搭配我的另一个项目 School-Partners学习伴侣
微信小程序而开发的。是一个采用Taro
多端框架开发的跨平台的小程序。感兴趣的可以看一下之前的文章
希望大佬们走过路过可以给个star鼓励一下,感激不尽~ https://github.com/zhcxk1998/School-Partners
这个是小程序的介绍文章 小程序介绍文章,使劲戳!
无图无真相!先上几个图~
运行截图
1. 登录界面
2. 题库管理
3. 修改题库
技术分析
就来说一下项目中自己推敲做出来的几个算是亮点的东西吧
1. 使用Hook封装API访问工具
本项目采用的UI框架是Ant-Design框架 因为这个项目的后台对于表格有着比较大的需求,而表格加载就需要使用到Loading
的状态,所以就特地封装一下便于之后使用
首先我们先新建一个文件useService.ts
然后我们先引入axios
来作为我们的api访问工具
import axios from 'axios'
const instance = axios.create({
baseURL: '/api',
timeout: 10000,
headers: {
'Content-Type': "application/json;charset=utf-8",
},
})
instance.interceptors.request.use(
config => {
const token = localStorage.getItem('token');
if (token) {
config.headers.common['Authorization'] = token;
}
return config
},
error => {
return Promise.reject(error)
}
)
instance.interceptors.response.use(
res => {
let { data, status } = res
if (status === 200) {
return data
}
return Promise.reject(data)
},
error => {
const { response: { status } } = error
switch (status) {
case 401:
localStorage.removeItem('token')
window.location.href = './#/login'
break;
case 504:
message.error('代理请求失败')
}
return Promise.reject(error)
}
)
先将axios
的拦截器,基本配置这些写好先
接着我们实现一个获取接口信息的方法useServiceCallback
const useServiceCallback = (fetchConfig: FetchConfig) => {
// 定义状态,包括返回信息,错误信息,加载状态等
const [isLoading, setIsLoading] = useState(false)
const [response, setResponse] = useState(null)
const [error, setError] = useState(null)
const { url, method, params = {}, config = {} } = fetchConfig
const callback = useCallback(
() => {
setIsLoading(true)
setError(null)
// 调用axios来进行接口访问,并且将传来的参数传进去
instance(url, {
method,
data: params,
...config
})
.then((response: any) => {
// 获取成功后,则将loading状态恢复,并且设置返回信息
setIsLoading(false)
setResponse(Object.assign({}, response))
})
.catch((error: any) => {
const { response: { data } } = error
const { data: { msg } } = data
message.error(msg)
setIsLoading(false)
setError(Object.assign({}, error))
})
}, [fetchConfig]
)
return [callback, { isLoading, error, response }] as const
}
这样就完成了主体部分了,可以利用这个hook来进行接口访问,接下来我们再做一点小工作
const useService = (fetchConfig: FetchConfig) => {
const preParams = useRef({})
const [callback, { isLoading, error, response }] = useServiceCallback(fetchConfig)
useEffect(() => {
if (preParams.current !== fetchConfig && fetchConfig.url !== '') {
preParams.current = fetchConfig
callback()
}
})
return { isLoading, error, response }
}
export default useService
我们定义一个useService的方法,我们通过定义一个useRef
来判断前后传过来的参数是否一致,如果不一样且接口访问配置信息的url
不为空就可以开始调用useServiceCallback
方法来进行接口访问了
具体使用如下:
我们先在组件内render外使用这个钩子,并且定义好返回的信息 接口返回体如下
const { isLoading = false, response } = useService(fetchConfig)
const { data = {} } = response || {}
const { exerciseList = [], total: totalPage = 0 } = data
因为我们这个hook是依赖fetchConfig
这个对象的,这里是他的类型
export interface FetchConfig {
url: string,
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
params?: object,
config?: object
}
所以我们只需要再页面加载时候调用useEffect
来进行更新这个fetchConfig
就可以触发这个获取数据的hook啦
const [fetchConfig, setFetchConfig] = useState({
url: '', method: 'GET', params: {}, config: {}
})
...
useEffect(() => {
const fetchConfig: FetchConfig = {
url: '/exercises',
method: 'GET',
params: {},
config: {}
}
setFetchConfig(Object.assign({}, fetchConfig))
}, [fetchFlag])
这样就大功告成啦!然后我们再到表格组件内传入相关数据就可以啦
setCurrentPage(pageNo)
}}
locale={
{
emptyText:
}}
/>
大功告成!!
2. 实现懒加载通用组件
我们这里使用的是react-loadable
这个组件,挺好用的嘿嘿,搭配nprogress
来进行过渡处理,具体效果参照github
网站上的加载效果
我们先封装好一个组件,在components/LoadableComponent
内定义如下内容
import React, { useEffect, FC } from 'react'
import Loadable from 'react-loadable'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
const LoadingPage: FC = () => {
useEffect(() => {
NProgress.start()
return () => {
NProgress.done()
}
}, [])
return (
)
}
const LoadableComponent = (component: () => Promise) => Loadable({
loader: component,
loading: () => ,
})
export default LoadableComponent
我们先定义好一个组件LoadingPage
这个是我们再加载中的时候需要展示的页面,在useEffect
中使用nprogress
的加载条进行显示,组件卸载时候则结束,而下面的div
则可以由用户自己定义需要展示的样式效果
下面的LoadableCompoennt
就是我们这个的主体,我们需要获取到一个组件,赋值给loader
,具体的赋值方法如下,我们可以在项目内的pages
部分将所有需要展示的页面引入进来,再导出,这样就可以方便的实现所有页面的懒加载了
// 引入刚刚定义的懒加载组件
import { LoadableComponent } from '@/admin/components'
// 定义组件,传给LoadableCompoennt组件需要的组件信息
const Login = LoadableComponent(() => import('./Login'))
const Register = LoadableComponent(() => import('./Register'))
const Index = LoadableComponent(() => import('./Index/index'))
const ExerciseList = LoadableComponent(() => import('./ExerciseList'))
const ExercisePublish = LoadableComponent(() => import('./ExercisePublish'))
const ExerciseModify = LoadableComponent(() => import('./ExerciseModify'))
// 导出,到时候再从这个pages/index.ts中引入,即可拥有懒加载效果了
export {
Login,
Register,
Index,
ExerciseList,
ExercisePublish,
ExerciseModify
}
大功告成!!!
3. 使用嵌套路由
项目因为涉及到后台信息的管理,所以个人认为导航栏与主题信息栏应该一同显示,如同下图
这样可以清晰的展示出信息以及给用户提供导航效果
我们现在项目的routes/index.tsx
定义一个全局通用的路由组件
import React from 'react'
import {
Switch, Redirect, Route,
} from 'react-router-dom'
// 这个是私有路由,下面会提到
import PrivateRoute from '../components/PrivateRoute'
import { Login, Register } from '../pages'
import Main from '../components/Main/index'
const Routes = () => (
)
export default Routes
这里的意思就是,登录以及注册页面是独立开来的,而Main这个组件就是负责包裹导航条以及内容部分的组件啦
接下来看看components/Main
中的内容吧
import React, { ComponentType } from 'react'
import { Layout } from 'antd';
import HeaderNav from '../HeaderNav'
import ContentMain from '../ContentMain'
import SiderNav from '../SiderNav'
import './index.scss'
const Main = () => (
// 头部导航栏
// 侧边栏
// 主体内容
)
export default Main as ComponentType
接下来重点就是这个ContentMain
组件啦
import React, { FC } from 'react'
import { withRouter, Switch, Redirect, RouteComponentProps, Route } from 'react-router-dom'
import { Index, ExerciseList, ExercisePublish, ExerciseModify } from '@/admin/pages'
import './index.scss'
const ContentMain: FC = () => {
return (
)
}
export default withRouter(ContentMain)
这个就是一个嵌套路由啦,在这里面使用withRouter来包裹一下,然后在这里再次定义路由信息,这样就可以只切换主体部分的内容而不改变导航栏啦
大功告成!!!
4. 侧边栏的选中部分动态变化
通过图片我们可以看出,侧边导航栏有一个选中的内容,那么我们该如何判断不同的url页面对应哪一个选中部分呢?
const [selectedKeys, setSelectedKeys] = useState(['index'])
const [openedKeys, setOpenedKeys] = useState([''])
const { location: { pathname } } = props
const rank = pathname.split('/')
useEffect(() => {
switch (rank.length) {
case 2: // 一级目录
setSelectedKeys([pathname])
setOpenedKeys([''])
break
case 4: // 二级目录
setSelectedKeys([pathname])
setOpenedKeys([rank.slice(0, 3).join('/')])
break
}
}, [pathname])
这就是最重要的部分啦,我们通过定义几个状态selectedKeys
选中的条目,openedKeys
打开的多级导航栏
我们通过在页面加载时候,判断页面url路径,如果是一级目录,例如首页,就直接设置选中的条目即可,如果是二级目录,例如导航栏中内容管理/题库管理
这个功能,他的url链接是/admin/content/exercise-list
,所以我们的case 4
就可以捕获到啦,然后设置当前选中的条目以及打开的多级导航,具体的导航信息请看下面
首页
内容管理
}
>
题库管理
大功告成!!!
5. 使用JWTToken来验证用户登录状态以及返回信息
要想使用登录注册功能,还有用户权限的问题,我们就需要使用到这个token啦!为什么我们要使用token呢?而不是用传统的cookies呢,因为使用token可以避免跨域啊还有更多的复杂问题,大大简化我们的开发效率
本项目后台采用nodeJs来进行开发
我们先在后台定义一个工具utils/token.js
// token的秘钥,可以存在数据库中,我偷懒就卸载这里面啦hhh
const secret = "zhcxk1998"
const jwt = require('jsonwebtoken')
// 生成token的方法,注意前面一定要有Bearer ,注意后面有一个空格,我们设置的时间是1天过期
const generateToken = (payload = {}) => (
'Bearer ' + jwt.sign(payload, secret, { expiresIn: '1d' })
)
// 这里是获取token信息的方法
const getJWTPayload = (token) => (
jwt.verify(token.split(' ')[1], secret)
)
module.exports = {
generateToken,
getJWTPayload
}
这里采用的是jsonwebtoken
这个库,来进行token的生成以及验证。
有了这个token啦,我们就可以再登录或者注册的时候给用户返回一个token信息啦
router.post('/login', async (ctx) => {
const responseBody = {
code: 0,
data: {}
}
try {
if (登录成功) {
responseBody.data.msg = '登陆成功'
// 在这里就可以返回token信息给前端啦
responseBody.data.token = generateToken({ username })
responseBody.code = 200
} else {
responseBody.data.msg = '用户名或密码错误'
responseBody.code = 401
}
} catch (e) {
responseBody.data.msg = '用户名不存在'
responseBody.code = 404
} finally {
ctx.response.status = responseBody.code
ctx.response.body = responseBody
}
})
这样前端就可以获取这个token啦,前端部分只需要将token存入localStorage
中即可,不用担心localStorage
是永久保存,因为我们的token有个过期时间,所以不用担心
/* 登录成功 */
if (code === 200) {
const { msg, token } = data
// 登录成功后,将token存入localStorage中
localStorage.setItem('token', token)
message.success(msg)
props.history.push('/admin')
}
好嘞,现在前端获取token也搞定啦,接下来我们就需要在访问接口的时候带上这个token啦,这样才可以让后端知道这个用户的权限如何,是否过期等
需要传tokne给后端,我们可以通过每次接口都传一个字段token
,但是这样十分浪费成本,所以我们再封装好的axios
中,我们设置请求头信息即可
import axios from 'axios'
const instance = axios.create({
baseURL: '/api',
timeout: 10000,
headers: {
'Content-Type': "application/json;charset=utf-8",
},
})
instance.interceptors.request.use(
config => {
// 请求头带上token信息
const token = localStorage.getItem('token');
if (token) {
config.headers.common['Authorization'] = token;
}
return config
},
error => {
return Promise.reject(error)
}
)
...
export default instance
如上图所示,我们每次请求接口的时候就会带上这个请求头啦!那么接下来我们就谈谈后端如何获取这个token并且验证吧
有获取token,以及验证部分,那么就需要出动我们的中间件啦!
我们验证token的话,要是用户是访问的登录或者注册接口,那么这个时候token其实是没有作用哒,所以我们需要将它隔离一下,所以我们定义一个中间件,用来跳过某些路由,我们再middleware/verifyToken.js
中定义(这里我们采用koa-jwt
来验证token)
const koaJwt = require('koa-jwt')
const verifyToken = () => {
return koaJwt({ secret: 'zhcxk1998' }).unless({
path: [
/login/,
/register/
]
})
}
module.exports = verifyToken
这样就可以忽略这登录注册路由啦,别的路由就验证token
拦截已经成功啦,那么我们该如何捕获,然后进行处理呢?我们再middleware/interceptToken
定义一个中间件,来处理捕获的token信息
const interceptToken = async (ctx, next) => {
return await next().catch((err) => {
const { status } = err
if (status === 401) {
ctx.response.status = 401
ctx.response.body = {
code: 401,
data: {
msg: '请登录后重试'
}
}
} else {
throw err
}
})
}
module.exports = () => (
interceptToken
)
由于koa-jwt
拦截的token,如果过期,他会自动抛出一个401的异常以表示该token已经过期,所以我们只需要判断这个状态status
然后进行处理即可
好嘞,中间件也定义好了,我们就在后端服务中使用起来吧!
const Koa = require('koa')
const Router = require('koa-router');
const bodyParser = require('koa-bodyparser')
const cors = require('koa2-cors');
const routes = require('../routes/routes')
const router = new Router()
const admin = new Koa();
const {
verifyToken,
interceptToken
} = require('../middleware')
const {
login,
info,
register,
exercises
} = require('../routes/admin')
admin.use(cors())
admin.use(bodyParser())
/* 拦截token */
admin.use(interceptToken())
admin.use(verifyToken())
/* 管理端 */
admin.use(routes(router, { login, info, register, exercises }))
module.exports = admin
我们直接使用router.use()
的方法就可以使用中间件啦,这里要记住!验证拦截token一定要在路由信息之前,否则是拦截不到的哟(如果在后面,路由都先执行了,还拦截啥嘛!)
大功告成!!!
6. 密码使用加密加盐的方式存储
我们在处理用户的信息的时候,需要存储密码,但是直接存储肯定不安全啦!所以我们需要加密以及加盐的处理,在这里我用到的是crypto
这个库
首先我们再utils/encrypt.js
中定义一个工具函数用来生成盐值以及获取加密信息
const crypto = require('crypto')
// 获取随机盐值,例如 c6ab1 这样子的字符串
const getRandomSalt = () => {
const start = Math.floor(Math.random() * 5)
const count = start + Math.ceil(Math.random() * 5)
return crypto.randomBytes(10).toString('hex').slice(start, count)
}
// 获取密码转换成md5之后的加密信息
const getEncrypt = (password) => {
return crypto.createHash('md5').update(password).digest('hex')
}
module.exports = {
getRandomSalt,
getEncrypt
}
这样我们就可以通过验证密码与数据库中加密的信息对不对得上,来判断是否登录成功等等
我们现在注册中使用上,当然我们需要两个表进行数据存储,一个是用户信息,一个是用户密码表,这样分开更加安全,例如这样
这样就可以将用户信息还有密码分开存放,更加安全,这里就不重点叙述啦
const { getRandomSalt, getEncrypt } = require('../../utils/encrypt')
// 注册部分
router.post('/register', async (ctx) => {
const { username, password, phone, email } = ctx.request.body
// 获取盐值以及加密后的信息
const salt = getRandomSalt()
// 数据库存放的密码是由用户输入的密码加上随机盐值,然后再进行加密所得到的的炒鸡加密密码
const encryptPassword = getEncrypt(password + salt)
// 插入用户信息,以及获取这个的id
const { insertId: user_id } = await query(INSERT_TABLE('user_info'), { username, phone, email });
// 插入用户密码信息,user_id与上面对应
await query(INSERT_TABLE('user_password'), {
user_id,
password: encryptPassword,
salt
})
...
})
接下来再来看登录部分,登录的话,就需要从用户密码表中取出加密密码,以及盐值,然后进行对比
// 通过用户名,先获取加密密码以及盐值
const { password: verifySign, salt } = await query(`select password, salt from user_password where user_id = '${userId}'`)[0]
// 这个就是用户输入的密码加上盐值一起加密后的密码
const sign = getEncrypt(password + salt)
// 这个加密的密码与数据库中加密的密码对比,如果一样则登陆成功
if (sign === verifySign) {
responseBody.data.msg = '登陆成功'
responseBody.data.token = generateToken({ username })
responseBody.code = 200
} else {
responseBody.data.msg = '用户名或密码错误'
responseBody.code = 401
}
大功告成!!!
结语
大部分的内容就大概这样子,这是自己开发中遇到的小问题还有解决方法,希望对大家有所帮助,大家一起成长!现在得看看面试题准备一波春招了,不然大学毕业了都找不到工作啦!有时间再继续更新这个文章!
最后还是顺便求一波star还有点赞!!!
github项目猛戳进来star一下嘿嘿 小程序介绍文章,使劲戳!
你可能感兴趣的:(node.js,reactjs,typescript,前端,jwt)
Long类型前后端数据不一致
igotyback
前端
响应给前端的数据浏览器控制台中response中看到的Long类型的数据是正常的到前端数据不一致前后端数据类型不匹配是一个常见问题,尤其是当后端使用Java的Long类型(64位)与前端JavaScript的Number类型(最大安全整数为2^53-1,即16位)进行数据交互时,很容易出现精度丢失的问题。这是因为JavaScript中的Number类型无法安全地表示超过16位的整数。为了解决这个问
DIV+CSS+JavaScript技术制作网页(旅游主题网页设计与制作)云南大理
STU学生网页设计
网页设计 期末网页作业 html静态网页 html5期末大作业 网页设计 web大作业
️精彩专栏推荐作者主页:【进入主页—获取更多源码】web前端期末大作业:【HTML5网页期末作业(1000套)】程序员有趣的告白方式:【HTML七夕情人节表白网页制作(110套)】文章目录二、网站介绍三、网站效果▶️1.视频演示2.图片演示四、网站代码HTML结构代码CSS样式代码五、更多源码二、网站介绍网站布局方面:计划采用目前主流的、能兼容各大主流浏览器、显示效果稳定的浮动网页布局结构。网站程
【加密社】Solidity 中的事件机制及其应用
加密社
闲侃 区块链 智能合约 区块链
加密社引言在Solidity合约开发过程中,事件(Events)是一种非常重要的机制。它们不仅能够让开发者记录智能合约的重要状态变更,还能够让外部系统(如前端应用)监听这些状态的变化。本文将详细介绍Solidity中的事件机制以及如何利用不同的手段来触发、监听和获取这些事件。事件存储的地方当我们在Solidity合约中使用emit关键字触发事件时,该事件会被记录在区块链的交易收据中。具体而言,事件
关于城市旅游的HTML网页设计——(旅游风景云南 5页)HTML+CSS+JavaScript
二挡起步
web前端期末大作业 javascript html css 旅游 风景
⛵源码获取文末联系✈Web前端开发技术描述网页设计题材,DIV+CSS布局制作,HTML+CSS网页设计期末课程大作业|游景点介绍|旅游风景区|家乡介绍|等网站的设计与制作|HTML期末大学生网页设计作业,Web大学生网页HTML:结构CSS:样式在操作方面上运用了html5和css3,采用了div+css结构、表单、超链接、浮动、绝对定位、相对定位、字体样式、引用视频等基础知识JavaScrip
HTML网页设计制作大作业(div+css) 云南我的家乡旅游景点 带文字滚动
二挡起步
web前端期末大作业 web设计网页规划与设计 html css javascript dreamweaver 前端
Web前端开发技术描述网页设计题材,DIV+CSS布局制作,HTML+CSS网页设计期末课程大作业游景点介绍|旅游风景区|家乡介绍|等网站的设计与制作HTML期末大学生网页设计作业HTML:结构CSS:样式在操作方面上运用了html5和css3,采用了div+css结构、表单、超链接、浮动、绝对定位、相对定位、字体样式、引用视频等基础知识JavaScript:做与用户的交互行为文章目录前端学习路线
node.js学习
小猿L
node.js node.js 学习 vim
node.js学习实操及笔记温故node.js,node.js学习实操过程及笔记~node.js学习视频node.js官网node.js中文网实操笔记githubcsdn笔记为什么学node.js可以让别人访问我们编写的网页为后续的框架学习打下基础,三大框架vuereactangular离不开node.jsnode.js是什么官网:node.js是一个开源的、跨平台的运行JavaScript的运行
springboot+vue项目实战一-创建SpringBoot简单项目
苹果酱0567
面试题汇总与解析 spring boot 后端 java 中间件 开发语言
这段时间抽空给女朋友搭建一个个人博客,想着记录一下建站的过程,就当做笔记吧。虽然复制zjblog只要一个小时就可以搞定一个网站,或者用cms系统,三四个小时就可以做出一个前后台都有的网站,而且想做成啥样也都行。但是就是要从新做,自己做的意义不一样,更何况,俺就是专门干这个的,嘿嘿嘿要做一个网站,而且从零开始,首先呢就是技术选型了,经过一番思量决定选择-SpringBoot做后端,前端使用Vue做一
博客网站制作教程
2401_85194651
java maven
首先就是技术框架:后端:Java+SpringBoot数据库:MySQL前端:Vue.js数据库连接:JPA(JavaPersistenceAPI)1.项目结构blog-app/├──backend/│├──src/main/java/com/example/blogapp/││├──BlogApplication.java││├──config/│││└──DatabaseConfig.java
vue 创建项目报错:command failed: npm install --loglevel error
那鱼、会飞
vue.js vue-cli3
这个问题其实很好解决,只是很多种情况,逐一排除即可。稳下心来~vuecli3创建项目我的node版本是node14.15.0,(永远不要尝试最新版本)node各种版本下载地址:以往的版本|Node.js(nodejs.org)vue/
[email protected] @vue/
[email protected] (注意vue/cli2和vue/cli3的下载命名有所改变,2是-形式,3是/形式)其实报错
更改npm镜像源为淘宝镜像
骆小骆
基于node.js
npm常用指令后缀*最近复习了一下node.js整理了一下跟node.js相关的指令后缀*--save、-S参数意思是把模块的版本信息保存到dependencies(生产环境依赖)中,即你的package.json文件的dependencies字段中;–--save-dev、-D参数意思是把模块版本信息保存到devDependencies(开发环境依赖)中,即你的package.json文件的de
最简单将静态网页挂载到服务器上(不用nginx)
全能全知者
服务器 nginx 运维 前端 html 笔记
最简单将静态网页挂载到服务器上(不用nginx)如果随便弄个静态网页挂在服务器都要用nignx就太麻烦了,所以直接使用Apache来搭建一些简单前端静态网页会相对方便很多检查Web服务器服务状态:sudosystemctlstatushttpd#ApacheWeb服务器如果发现没有安装web服务器:安装Apache:sudoyuminstallhttpd启动Apache:sudosystemctl
补充元象二面
Redstone Monstrosity
前端 面试
1.请尽可能详细地说明,防抖和节流的区别,应用场景?你的回答中不要写出示例代码。防抖(Debounce)和节流(Throttle)是两种常用的前端性能优化技术,它们的主要区别在于如何处理高频事件的触发。以下是防抖和节流的区别和应用场景的详细说明:防抖和节流的定义防抖:在一段时间内,多次执行变为只执行最后一次。防抖的原理是,当事件被触发后,设置一个延迟定时器。如果在这个延迟时间内事件再次被触发,则重
微信小程序开发注意事项
jun778895
微信小程序 小程序
微信小程序开发是一个融合了前端开发、用户体验设计、后端服务(可选)以及微信小程序平台特性的综合性项目。这里,我将详细介绍一个典型的小程序开发项目的全过程,包括项目规划、设计、开发、测试及部署上线等各个环节,并尽量使内容达到或超过2000字的要求。一、项目规划1.1项目背景与目标假设我们要开发一个名为“智慧校园助手”的微信小程序,旨在为学生提供一站式校园生活服务,包括课程表查询、图书馆座位预约、食堂
字节二面
Redstone Monstrosity
前端 面试
1.假设你是正在面试前端开发工程师的候选人,面试官让你详细说出你上一段实习过程的收获和感悟。在上一段实习过程中,我获得了宝贵的实践经验和深刻的行业洞察,以下是我的主要收获和感悟:一、专业技能提升框架应用熟练度:通过实际项目,我深入掌握了React、Vue等前端框架的使用,不仅提升了编码效率,还学会了如何根据项目需求选择合适的框架。问题解决能力:在实习期间,我遇到了许多预料之外的技术难题。通过查阅文
前端代码上传文件
余生逆风飞翔
前端 javascript 开发语言
点击上传文件import{ElNotification}from'element-plus'import{API_CONFIG}from'../config/index.js'import{UploadFilled}from'@element-plus/icons-vue'import{reactive}from'vue'import{BASE_URL}from'../config/index'i
详解“c:/work/src/components/a/b.vue“‘ has no default export报错原因
hw_happy
开发语言 前端 vue.js javascript
前情提要在一个vue文件中需要引入定义的b.vue文件,但是提示b文件没有默认导出,对于vue2文件来说有exportdefault,在中,所有定义的变量、函数和组件都会自动被视为默认导出的组件内容。因此,不需要显式地使用exportdefault来导出组件。但是在我引用这个文件的时候还是提示了这个错误,原来是我的项目使用了ts和vite\webpack,因为TypeScript和Vue的默认导出
uniapp实现动态标记效果详细步骤【前端开发】
2401_85123349
uni-app
第二个点在于实现将已经被用户标记的内容在下一次获取后刷新它的状态为已标记。这是什么意思呢?比如说上面gif图中的这些人物对象,有一些已被该用户添加为关心,那么当用户下一次进入该页面时,这些已经被添加关心的对象需要以“红心”状态显现出来。这个点的难度还不算大,只需要在每一次获取后端的内容后对标记对象进行状态更新即可。II.动态标记效果实现思路和步骤首先,整体的思路是利用动态类名对不同的元素进行选择。
360前端星计划-动画可以这么玩
马小蜗
动画的基本原理定时器改变对象的属性根据新的属性重新渲染动画functionupdate(context){//更新属性}constticker=newTicker();ticker.tick(update,context);动画的种类1、JavaScript动画操作DOMCanvas2、CSS动画transitionanimation3、SVG动画SMILJS动画的优缺点优点:灵活度、可控性、性能
Vue + Express实现一个表单提交
九旬大爷的梦
最近在折腾一个cms系统,用的vue+express,但是就一个表单提交就弄了好久,记录一下。环境:Node10+前端:Vue服务端:Express依赖包:vueexpressaxiosexpress-formidableelement-ui(可选)前言:axiosget请求参数是:paramsaxiospost请求参数是:dataexpressget接受参数是req.queryexpresspo
vant-element-ts一起使用存在的问题
flynn_
问题总结 vue
由于vant-ui与element-ui部分组件存在冲突,导致在vue-typescript中出现错误:Subsequentpropertydeclarationsmusthavethesametype.Property'$notify'mustbeoftype'ElNotification',butherehastype'Notify'.方案:一个全局导入,一个按需导入,避免冲突的组件同时使用,
前端知识点
ZhangTao_zata
前端 javascript css
下面是一个最基本的html代码body{font-family:Arial,sans-serif;margin:20px;}//JavaScriptfunctionthatdisplaysanalertwhencalledfunctionshowMessage(){alert("Hello!Youclickedthebutton.");}MyFirstHTMLPageWelcometoMyPage
第三十一节:Vue路由:前端路由vs后端路由的了解
曹老师
1.认识前端路由和后端路由前端路由相对于后端路由而言的,在理解前端路由之前先对于路由有一个基本的了解路由:简而言之,就是把信息从原地址传输到目的地的活动对于我们来说路由就是:根据不同的url地址展示不同的页面内容1.1后端路由以前咱们接触比较多的后端路由,当改变url地址时,浏览器会向服务器发送请求,服务器根据这个url,返回不同的资源内容后端路由的特点就是前端每次跳转到不同url地址,都会重新访
华雁智科前端面试题
因为奋斗超太帅啦
前端笔试面试问题整理 javascript 开发语言 ecmascript
1.var变量的提升题目:vara=1functionfun(){console.log(b)varb=2}fun()console.log(a)正确输出结果:undefined、1答错了,给一个大嘴巴子,错误答案输出结果为:2,1此题主要考察var定义的变量,作用域提升的问题,相当于varaa=1functionfun(){varbconsole.log(b)b=2}fun()console.l
如何建设数据中台(五)——数据汇集—打破企业数据孤岛
weixin_47088026
学习记录和总结 中台 数据中台 程序人生 经验分享
数据汇集——打破企业数据孤岛要构建企业级数据中台,第一步就是将企业内部各个业务系统的数据实现互通互联,打破数据孤岛,主要通过数据汇聚和交换来实现。企业采集的数据可以是线上采集、线下数据采集、互联网数据采集、内部数据采集等。线上数据采集主要载体分为互联网和移动互联网两种,对应有系统平台、网页、H5、小程序、App等,可以采用前端或后端埋点方式采集数据。线下数据采集主要是通过硬件来采集,例如:WiFi
分布式锁和spring事务管理
暴躁的鱼
锁及事务 分布式 spring java
最近开发一个小程序遇到一个需求需要实现分布式事务管理业务需求用户在使用小程序的过程中可以查看景点,对景点地区或者城市标记是否想去,那么需要统计一个地点被标记的人数,以及记录某个用户对某个地点是否标记为想去,用两个表存储数据,一个地点表记录改地点被标记的次数,一个用户意向表记录某个用户对某个地点是否标记为想去。由于可能有多个用户同时标记一个地点,每个用户在前端点击想去按钮之后,后台接收到请求,从数据
前端CSS面试常见题
剑亦未配妥
前端面试 前端 css 面试
边界塌陷盒模型有两种:W3C盒模型和IE盒模型,区别在于宽度是否包含边框定义:同时给兄弟/父子盒模型设置上下边距,理论上边距值是两者之和,实际上不是注意:浮动和定位不会产生边界塌陷;只有块级元素垂直方向才会产生margin合并margin计算方案margin同为正负:取绝对值大的值一正一负:求和父子元素边界塌陷解决父元素可以通过调整padding处理;设置overflowhidden,触发BFC子
【JS】前端文件读取FileReader操作总结
程序员-张师傅
前端 前端 javascript 开发语言
前端文件读取FileReader操作总结FileReader是JavaScript中的一个WebAPI,它允许web应用程序异步读取用户计算机上的文件(或原始数据缓冲区)的内容,例如读取文件以获取其内容,并在不将文件发送到服务器的情况下在客户端使用它。这对于处理图片、文本文件等非常有用,尤其是当你想要在用户界面中即时显示文件内容或进行文件预览时。创建FileReader对象首先,你需要创建一个Fi
【前端】vue 报错:The template root requires exactly one element
程序员-张师傅
前端 前端 vue.js javascript
【前端】vue报错:Thetemplaterootrequiresexactlyoneelement在Vue.js中,当你遇到错误“Thetemplaterootrequiresexactlyoneelement”时,这通常意味着你的Vue组件的模板(template)根节点不是单一的元素。Vue要求每个组件的模板必须有一个根元素来包裹所有的子元素。这个错误通常出现在以下几种情况:模板中有多个并行
从单体到微服务:FastAPI ‘挂载’子应用程序的转变
黑金IT
fastapi 微服务 fastapi 架构
在现代Web应用开发中,模块化架构是一种常见的设计模式,它有助于将大型应用程序分解为更小、更易于管理的部分。FastAPI,作为一个高性能的PythonWeb框架,提供了强大的支持来实现这种模块化设计。通过“挂载”子应用程序,我们可以为不同的功能区域(如前端接口、管理员接口和用户中心)创建独立的应用程序,并将它们整合到一个主应用程序中。本文将详细介绍如何在FastAPI中使用“挂载”子应用程序的方
创建一个完整的购物商城系统是一个复杂的项目,涉及前端(用户界面)、后端(服务器逻辑)、数据库等多个部分。由于篇幅限制,我无法在这里提供一个完整的系统代码,但我可以分别给出一些关键部分的示例代码,涵盖几
uthRaman
前端 ui 服务器
前端(HTML/CSS/JavaScript)grsyzp.cnHTML页面结构(index.html)html购物商城欢迎来到购物商城JavaScript(Ajax请求商品数据,app.js)javascriptdocument.addEventListener('DOMContentLoaded',function(){fetch('/api/products').then(response=
PHP,安卓,UI,java,linux视频教程合集
cocos2d-x小菜
java UI linux PHP android
╔-----------------------------------╗┆
zookeeper admin 笔记
braveCS
zookeeper
Required Software
1) JDK>=1.6
2)推荐使用ensemble的ZooKeeper(至少3台),并run on separate machines
3)在Yahoo!,zk配置在特定的RHEL boxes里,2个cpu,2G内存,80G硬盘
数据和日志目录
1)数据目录里的文件是zk节点的持久化备份,包括快照和事务日
Spring配置多个连接池
easterfly
spring
项目中需要同时连接多个数据库的时候,如何才能在需要用到哪个数据库就连接哪个数据库呢?
Spring中有关于dataSource的配置:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
&nb
Mysql
171815164
mysql
例如,你想myuser使用mypassword从任何主机连接到mysql服务器的话。
GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'%'IDENTIFIED BY 'mypassword' WI
TH GRANT OPTION;
如果你想允许用户myuser从ip为192.168.1.6的主机连接到mysql服务器,并使用mypassword作
CommonDAO(公共/基础DAO)
g21121
DAO
好久没有更新博客了,最近一段时间工作比较忙,所以请见谅,无论你是爱看呢还是爱看呢还是爱看呢,总之或许对你有些帮助。
DAO(Data Access Object)是一个数据访问(顾名思义就是与数据库打交道)接口,DAO一般在业
直言有讳
永夜-极光
感悟 随笔
1.转载地址:http://blog.csdn.net/jasonblog/article/details/10813313
精华:
“直言有讳”是阿里巴巴提倡的一种观念,而我在此之前并没有很深刻的认识。为什么呢?就好比是读书时候做阅读理解,我喜欢我自己的解读,并不喜欢老师给的意思。在这里也是。我自己坚持的原则是互相尊重,我觉得阿里巴巴很多价值观其实是基本的做人
安装CentOS 7 和Win 7后,Win7 引导丢失
随便小屋
centos
一般安装双系统的顺序是先装Win7,然后在安装CentOS,这样CentOS可以引导WIN 7启动。但安装CentOS7后,却找不到Win7 的引导,稍微修改一点东西即可。
一、首先具有root 的权限。
即进入Terminal后输入命令su,然后输入密码即可
二、利用vim编辑器打开/boot/grub2/grub.cfg文件进行修改
v
Oracle备份与恢复案例
aijuans
oracle
Oracle备份与恢复案例
一. 理解什么是数据库恢复当我们使用一个数据库时,总希望数据库的内容是可靠的、正确的,但由于计算机系统的故障(硬件故障、软件故障、网络故障、进程故障和系统故障)影响数据库系统的操作,影响数据库中数据的正确性,甚至破坏数据库,使数据库中全部或部分数据丢失。因此当发生上述故障后,希望能重构这个完整的数据库,该处理称为数据库恢复。恢复过程大致可以分为复原(Restore)与
JavaEE开源快速开发平台G4Studio v5.0发布
無為子
我非常高兴地宣布,今天我们最新的JavaEE开源快速开发平台G4Studio_V5.0版本已经正式发布。
访问G4Studio网站
http://www.g4it.org
2013-04-06 发布G4Studio_V5.0版本
功能新增
(1). 新增了调用Oracle存储过程返回游标,并将游标映射为Java List集合对象的标
Oracle显示根据高考分数模拟录取
百合不是茶
PL/SQL编程 oracle例子 模拟高考录取 学习交流
题目要求:
1,创建student表和result表
2,pl/sql对学生的成绩数据进行处理
3,处理的逻辑是根据每门专业课的最低分线和总分的最低分数线自动的将录取和落选
1,创建student表,和result表
学生信息表;
create table student(
student_id number primary key,--学生id
优秀的领导与差劲的领导
bijian1013
领导 管理 团队
责任
优秀的领导:优秀的领导总是对他所负责的项目担负起责任。如果项目不幸失败了,那么他知道该受责备的人是他自己,并且敢于承认错误。
差劲的领导:差劲的领导觉得这不是他的问题,因此他会想方设法证明是他的团队不行,或是将责任归咎于团队中他不喜欢的那几个成员身上。
努力工作
优秀的领导:团队领导应该是团队成员的榜样。至少,他应该与团队中的其他成员一样努力工作。这仅仅因为他
js函数在浏览器下的兼容
Bill_chen
jquery 浏览器 IE DWR ext
做前端开发的工程师,少不了要用FF进行测试,纯js函数在不同浏览器下,名称也可能不同。对于IE6和FF,取得下一结点的函数就不尽相同:
IE6:node.nextSibling,对于FF是不能识别的;
FF:node.nextElementSibling,对于IE是不能识别的;
兼容解决方式:var Div = node.nextSibl
【JVM四】老年代垃圾回收:吞吐量垃圾收集器(Throughput GC)
bit1129
垃圾回收
吞吐量与用户线程暂停时间
衡量垃圾回收算法优劣的指标有两个:
吞吐量越高,则算法越好
暂停时间越短,则算法越好
首先说明吞吐量和暂停时间的含义。
垃圾回收时,JVM会启动几个特定的GC线程来完成垃圾回收的任务,这些GC线程与应用的用户线程产生竞争关系,共同竞争处理器资源以及CPU的执行时间。GC线程不会对用户带来的任何价值,因此,好的GC应该占
J2EE监听器和过滤器基础
白糖_
J2EE
Servlet程序由Servlet,Filter和Listener组成,其中监听器用来监听Servlet容器上下文。
监听器通常分三类:基于Servlet上下文的ServletContex监听,基于会话的HttpSession监听和基于请求的ServletRequest监听。
ServletContex监听器
ServletContex又叫application
博弈AngularJS讲义(16) - 提供者
boyitech
js AngularJS api Angular Provider
Angular框架提供了强大的依赖注入机制,这一切都是有注入器(injector)完成. 注入器会自动实例化服务组件和符合Angular API规则的特殊对象,例如控制器,指令,过滤器动画等。
那注入器怎么知道如何去创建这些特殊的对象呢? Angular提供了5种方式让注入器创建对象,其中最基础的方式就是提供者(provider), 其余四种方式(Value, Fac
java-写一函数f(a,b),它带有两个字符串参数并返回一串字符,该字符串只包含在两个串中都有的并按照在a中的顺序。
bylijinnan
java
public class CommonSubSequence {
/**
* 题目:写一函数f(a,b),它带有两个字符串参数并返回一串字符,该字符串只包含在两个串中都有的并按照在a中的顺序。
* 写一个版本算法复杂度O(N^2)和一个O(N) 。
*
* O(N^2):对于a中的每个字符,遍历b中的每个字符,如果相同,则拷贝到新字符串中。
* O(
sqlserver 2000 无法验证产品密钥
Chen.H
sql windows SQL Server Microsoft
在 Service Pack 4 (SP 4), 是运行 Microsoft Windows Server 2003、 Microsoft Windows Storage Server 2003 或 Microsoft Windows 2000 服务器上您尝试安装 Microsoft SQL Server 2000 通过卷许可协议 (VLA) 媒体。 这样做, 收到以下错误信息CD KEY的 SQ
[新概念武器]气象战争
comsci
气象战争的发动者必须是拥有发射深空航天器能力的国家或者组织....
原因如下:
地球上的气候变化和大气层中的云层涡旋场有密切的关系,而维持一个在大气层某个层次
oracle 中 rollup、cube、grouping 使用详解
daizj
oracle grouping rollup cube
oracle 中 rollup、cube、grouping 使用详解 -- 使用oracle 样例表演示 转自namesliu
-- 使用oracle 的样列库,演示 rollup, cube, grouping 的用法与使用场景
--- ROLLUP , 为了理解分组的成员数量,我增加了 分组的计数 COUNT(SAL)
技术资料汇总分享
Dead_knight
技术资料汇总 分享
本人汇总的技术资料,分享出来,希望对大家有用。
http://pan.baidu.com/s/1jGr56uE
资料主要包含:
Workflow->工作流相关理论、框架(OSWorkflow、JBPM、Activiti、fireflow...)
Security->java安全相关资料(SSL、SSO、SpringSecurity、Shiro、JAAS...)
Ser
初一下学期难记忆单词背诵第一课
dcj3sjt126com
english word
could 能够
minute 分钟
Tuesday 星期二
February 二月
eighteenth 第十八
listen 听
careful 小心的,仔细的
short 短的
heavy 重的
empty 空的
certainly 当然
carry 携带;搬运
tape 磁带
basket 蓝子
bottle 瓶
juice 汁,果汁
head 头;头部
截取视图的图片, 然后分享出去
dcj3sjt126com
OS Objective-C
OS 7 has a new method that allows you to draw a view hierarchy into the current graphics context. This can be used to get an UIImage very fast.
I implemented a category method on UIView to get the vi
MySql重置密码
fanxiaolong
MySql重置密码
方法一:
在my.ini的[mysqld]字段加入:
skip-grant-tables
重启mysql服务,这时的mysql不需要密码即可登录数据库
然后进入mysql
mysql>use mysql;
mysql>更新 user set password=password('新密码') WHERE User='root';
mysq
Ehcache(03)——Ehcache中储存缓存的方式
234390216
ehcache MemoryStore DiskStore 存储 驱除策略
Ehcache中储存缓存的方式
目录
1 堆内存(MemoryStore)
1.1 指定可用内存
1.2 驱除策略
1.3 元素过期
2 &nbs
spring mvc中的@propertysource
jackyrong
spring mvc
在spring mvc中,在配置文件中的东西,可以在java代码中通过注解进行读取了:
@PropertySource 在spring 3.1中开始引入
比如有配置文件
config.properties
mongodb.url=1.2.3.4
mongodb.db=hello
则代码中
@PropertySource(&
重学单例模式
lanqiu17
单例 Singleton 模式
最近在重新学习设计模式,感觉对模式理解更加深刻。觉得有必要记下来。
第一个学的就是单例模式,单例模式估计是最好理解的模式了。它的作用就是防止外部创建实例,保证只有一个实例。
单例模式的常用实现方式有两种,就人们熟知的饱汉式与饥汉式,具体就不多说了。这里说下其他的实现方式
静态内部类方式:
package test.pattern.singleton.statics;
publ
.NET开源核心运行时,且行且珍惜
netcome
java .net 开源
背景
2014年11月12日,ASP.NET之父、微软云计算与企业级产品工程部执行副总裁Scott Guthrie,在Connect全球开发者在线会议上宣布,微软将开源全部.NET核心运行时,并将.NET 扩展为可在 Linux 和 Mac OS 平台上运行。.NET核心运行时将基于MIT开源许可协议发布,其中将包括执行.NET代码所需的一切项目——CLR、JIT编译器、垃圾收集器(GC)和核心
使用oscahe缓存技术减少与数据库的频繁交互
Everyday都不同
Web 高并发 oscahe缓存
此前一直不知道缓存的具体实现,只知道是把数据存储在内存中,以便下次直接从内存中读取。对于缓存的使用也没有概念,觉得缓存技术是一个比较”神秘陌生“的领域。但最近要用到缓存技术,发现还是很有必要一探究竟的。
缓存技术使用背景:一般来说,对于web项目,如果我们要什么数据直接jdbc查库好了,但是在遇到高并发的情形下,不可能每一次都是去查数据库,因为这样在高并发的情形下显得不太合理——
Spring+Mybatis 手动控制事务
toknowme
mybatis
@Override
public boolean testDelete(String jobCode) throws Exception {
boolean flag = false;
&nbs
菜鸟级的android程序员面试时候需要掌握的知识点
xp9802
android
熟悉Android开发架构和API调用
掌握APP适应不同型号手机屏幕开发技巧
熟悉Android下的数据存储
熟练Android Debug Bridge Tool
熟练Eclipse/ADT及相关工具
熟悉Android框架原理及Activity生命周期
熟练进行Android UI布局
熟练使用SQLite数据库;
熟悉Android下网络通信机制,S