### 此后台系统是为了搭配我的另一个项目 `School-Partners学习伴侣`微信小程序而开发的。是一个采用`Taro`多端框架开发的跨平台的小程序。感兴趣的可以看一下之前的文章
这篇文章主要是分享一下在开发这个东东的时候,遇到的一些问题,以及一些技术的巧妙的方法分享给大家,如果对大家有帮助的话,请给我点赞一下给个star鼓励一下~无比感谢嘿嘿

希望大佬们走过路过可以给个star鼓励一下~感激不尽~这个是小程序还有后台都整合在一起的仓库,`client`是小程序端的前端代码,`server`是小程序端和管理端的后台,`admin`是管理端的前端代码
### 1. 登录界面

### 2. 题库管理

### 3. 修改题库

### 1. 使用Hook封装API访问工具
const [callback, { isLoading, error, response }] = useServiceCallback(fetchConfig)
我们定义一个useService的方法,我们通过定义一个`useRef`来判断前后传过来的参数是否一致,如果不一样且接口访问配置信息的`url`不为空就可以开始调用`useServiceCallback`方法来进行接口访问了

...
rowSelection={rowSelection}
dataSource={exerciseList}
columns={columns}
rowKey="exerciseId"
scroll={{
y: "calc(100vh - 300px)"
}}
loading={{
spinning: isLoading,
tip: "加载中...",
size: "large"
}}
pagination={{
pageSize: 10,
total: totalPage,
current: currentPage,
onChange: (pageNo) => setCurrentPage(pageNo)
}}
locale={{
emptyText:
image={Empty.PRESENTED_IMAGE_SIMPLE}
description="暂无数据" />
}}
/>
```
大功告成!!
### 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])
```
如果是用React的没有使用到hook,则这里可以使用`componentWillReceiveProps()` 还有 `componentDidMount()`搭配使用,意思就是页面加载好之后设置一下这个选中,然后有更新也设置一下
这就是最重要的部分啦,我们通过定义几个状态`selectedKeys`选中的条目,`openedKeys`打开的多级导航栏
我们通过在页面加载时候,判断页面url路径,如果是一级目录,例如首页,就直接设置选中的条目即可,如果是二级目录,例如导航栏中`内容管理/题库管理`这个功能,他的url链接是`/admin/content/exercise-list`,所以我们的`case 4`就可以捕获到啦,然后设置当前选中的条目以及打开的多级导航,具体的导航信息请看下面
```
mode="inline"
defaultSelectedKeys={['/admin']}
selectedKeys={selectedKeys}
openKeys={openedKeys}
onOpenChange={handleMenuChange}
>
首页
key="/admin/content"
title={
内容管理
}
>
题库管理
```
这样我们无论是通过点击侧边导航栏,或者是直接输入url访问页面,这个导航栏选中的条目就会与我们访问的页面对应的啦~
大功告成!!!
### 5. 巧妙利用Antd表单来构造特殊的数据结构
使用过Antd表单的胖友们一定知道`this.props.form.validateFields()`这个方法吧嘿嘿,他是如果验证成功就返回表单的值给你,不用自己去绑定输入组件的值,很方便,来看看官方的例子

可以看到,最简单的一个登录框,然后我们就可以得到一组数据啦,不过我们可以发现,这些数据就是一个对象中的几个值。
假如我们有很多数据,想用多个对象来构造数据结构,这应该怎么办呢,就例如这样子的数据结构,我们还是举上面这个例子

假如吼,我们提交后台的数据需要是这样子的数据结构,用户名和密码在`userInfo`这个对象内,然后是否记住密码是在`other`对象里面,自己得到数据之后再构造又十分麻烦,这可怎么办呢。
在此之前,我们不如看看官方给的另一个例子,一个动态添加表单项的例子,于此我们就可以发挥想象力,然后就可以解决我们上面的问题啦

可以看到这个动态添加表单项的,是以数组形式来存储数据的,他的代码是这样的
```
{getFieldDecorator(`names[${k}]`, {
validateTrigger: ['onChange', 'onBlur'],
rules: [
{
required: true,
whitespace: true,
message: "Please input passenger's name or delete this field.",
},
],
})( )}
```
Antd表单的构造数据关键就在于里面的`getFieldDecorator`内的第一个参数,也就是我们的`propName`用来指定数据叫啥,跟之后验证表单传回的值是对应的了。这就给了我们一个很大的提示啦!!
> 这个`propName`叫什么,之后生成的数据结构里面就是什么,是`a`,之后数据就对应`a`,是`b`,就对应`b`
这里通过一个`names[$k]`,就可以让之后得到的数据变成一个数组`names:Array(2): ['1', '2']`这样子的形式,那么我们稍加改造一下,就可以变成对象的形式啦!下面看看代码,其实也很简单!
```
{getFieldDecorator(`topicList[${index}].topicContent`, {
rules: TopicContentRules,
initialValue: topicList[index].topicContent
})( )}
```
这里我就直接举项目中题库提交的例子啦,`topicList`是一个列表,里面存的是每一个题目对应的数据对象

这里的`propName`,我指定成了`topicList[$(index)]`就代表,这个属于这个列表里面的第几个对象,然后后面的`.topicContent`就代表这个对象里面的值是什么,最后我们的出的结构就是这样子的啦!

我们如愿得到了想要的数据结构了,这里面有对象,有数组,十分方便,可以灵活根据实际情况进行使用,关键就在于`getFieldDecorator()`里面的`propName`,直接以对象的形式命名,就可以啦!就按照下面这种形式就好啦!
```
{getFieldDecorator(`object.itemName`, {
initialValue: 'BB小天使'
})( )}
```
之后就可以得到对象类型的表单值啦!
大功告成!!!
### 6. 后台接口获取信息后填充Antd表单
因为有一个题库修改的功能,所以打算获取完接口信息之后,直接将内容通过Antd表单的`setFields`的方法来直接填充表格中的信息,结果控制台报错了

看了看大致意思就是说emmmm不可以在渲染之前就设置表单的值,嘶~这可难受了,这时候想到他的表单内有一个`initialValue`的属性,是表单项的默认值,这可好办啦,这样我们先拉取信息,存入对象中,然后再通过这个属性给表单传值,果然不出所料,真的ok了没有报错了哈哈哈,具体看下面
```
// 定义选项列表来存储题库的题目列表信息
const [topicList, setTopicList] = useState([{
topicType: 1,
topicAnswer: [],
topicContent: '',
topicOptions: []
}])
// 定义题库基本信息对象
const [exerciseInfo, setExerciseInfo] = useState({
exerciseName: '',
exerciseContent: '',
exerciseDifficulty: 1,
exerciseType: 1,
isHot: false
})
// 首先先拉取信息,这就是题库的信息啦
const { data } = await http.get(`/exercises/${id}`)
const {
exerciseName,
exerciseContent,
exerciseDifficulty,
exerciseType,
isHot,
topicList } = data
topicList.forEach((_: any, index: number) => {
topicList[index].topicOptions = topicList[index].topicOptions.map((item: any) => item.option)
})
// 获取信息后,设置状态
setTopicList([...topicList])
setExerciseInfo({
exerciseName,
exerciseContent,
exerciseDifficulty,
exerciseType,
isHot,
})
```
这样我们就得到了题库信息的对象啦,待会我们就可以用来传默认值给表单啦!
```
// 这里就通过题库名称来做例子,就从刚才设置的信息对象中取值然后设置默认值就可以啦
{getFieldDecorator('exerciseName', {
rules: ExerciseNameRules,
initialValue: exerciseInfo.exerciseName
})( )}
```
因为题库的题目是有挺多,所以是一个列表,类似下图

所以我们实现设置好`topicList`这个数组来存储题目的信息,然后我们通过遍历这个列表来实现多题目编辑
```
{topicList && topicList.map((_: any, index: number) => {
return (
第{index + 1}题
type="delete"
theme="twoTone"
twoToneColor="#fa4b2a"
style={{ marginLeft: 16, display: topicList.length > 1 ? 'inline' : 'none' }}
onClick={() => handleTopicDeleteClick(index)} />
{getFieldDecorator(`topicList[${index}].topicContent`, {
rules: TopicContentRules,
initialValue: topicList[index].topicContent
})( )}
...... 省略一堆~
)
})}
新增题目
```
例如**题目内容**的话,我们就设置他的`initialValue`为`topicList[index].topicContent`即可,别的属性同理,然后点击新增题目按钮,就直接往topicList内添加对象信息即可完成题目列表的增加,点击删除图标,就删除列表中某一项,是不是十分方便!!哈哈哈
大功告成!!!
### 7. 使用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一定要在路由信息之前,否则是拦截不到的哟(如果在后面,路由都先执行了,还拦截啥嘛!)
大功告成!!!
### 8. 密码使用加密加盐的方式存储
我们在处理用户的信息的时候,需要存储密码,但是直接存储肯定不安全啦!所以我们需要加密以及加盐的处理,在这里我用到的是`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还有点赞!!!
何时才能上100点赞,100star啊呜呜呜
[github项目猛戳进来star一下嘿嘿](https://github.com/zhcxk1998/School-Partners)
[小程序介绍文章,使劲戳!](https://juejin.im/post/5dd161675188254efb3bceea)
你可能感兴趣的:(React + Node.JS 巧妙实现后台管理系统の各种小技巧(前后端))
【Spring Boot 实现 PDF 导出】
web14786210723
面试 学习路线 阿里巴巴 spring boot pdf 后端
SpringBoot实现PDF导出在SpringBoot应用程序中实现PDF导出功能,可以选择多种库和技术栈。每种方法都有其优缺点,适用于不同的场景。以下是四种常见的方式:iText、ApachePDFBox、JasperReports和Thymeleaf+FlyingSaucer。我将详细对比这些方法,并提供相应的代码示例。1.iText优点:丰富的API:支持复杂的PDF操作,如加密、数字签名
基于图像处理的裂缝检测与特征提取
机器懒得学习
图像处理 计算机视觉 人工智能
一、引言裂缝检测是基础设施监测中至关重要的一项任务,尤其是在土木工程和建筑工程领域。随着自动化技术的发展,传统的人工巡检方法逐渐被基于图像分析的自动化检测系统所取代。通过计算机视觉和图像处理技术,能够高效、精确地提取裂缝的几何特征,如长度、宽度、方向、面积等,从而为工程质量评估提供数据支持。本文将详细介绍一段用于裂缝检测与特征提取的Python代码,重点讲解其实现的核心算法与关键步骤,分析其应用场
OSPF协议五种网络类型中DR和BDR选举说明
路星辞*
网络 网络 智能路由器 运维 ospf
OSPF协议五种网络类型中DR和BDR选举说明OSPF链路类型有3种:点到点,广播型,NBMA(非广播-多路访问网络(Non-BroadcastMultipleAccess,NBMA))。在3种链路类型上扩展出5种网络类型:点到点,广播,NBMA,点到多点,虚链路。其中虚链路较为特殊,不针对具体链路,而NBMA链路对应NBMA和点到多点两种网络类型。以上是RFC的定义,在Cisco路由器的实现上,
快速排序_详解快速排序算法
网站推广优化yetaoaiueo
排序算法 算法
快速排序(Quicksort),计算机科学词汇,适用领域Pascal,c++等语言,是对冒泡排序算法的一种改进。快速排序的排序流程快速排序算法通过多次比较和交换来实现排序,其排序流程如下:(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于分界值,而右边部分中各元素都大于或等于分界值
浅谈十大源码交易平台,找源码不走弯路
17源码网
游戏 源代码管理
大家好啊,作为一名经历了无数代码风风雨雨的资深老码农,今天我就来跟你们聊聊十大源码交易平台。这可是我多年经验的结晶,希望你们能从中找到自己需要的宝贝。七爪网:七爪网,这名字很生动。七爪网提供各种类型的源码,包括游戏源码、分销商城源码、小程序源码等等,简直是码农的百宝箱。不管你是初学者还是经验丰富的老鸟,总能在这里找到适合的资源。而且,七爪网还提供详细的使用教程和技术支持,真是想得太周到了。86资源
自定义Agent组件
三月七꧁ ꧂
langchain+llm python 开发语言 microsoft gpt langchain javascript 前端
文章目录ReActAgent的实践工具组件和工具包组件工具组件的类型 一个Agent组件由两部分组成:tools(代理可以使用的工具)和AgentExecutor(决定采取哪种行动)。下面逐一介绍如何创建自定义Agent组件。Tool、AgentExecutor和BaseSingleActionAgent是从LangChain.agents模块中导人的类,用于创建自定义Agent组件和too
java实现数据上传到接口,Java 导入数据到Excel并提供文件下载接口
梨漾
java实现数据上传到接口
依赖net.sourceforge.jexcelapijxl2.6.12复制代码我们需要用到jxl包的类,而jxl.jar正是操作excel表格的工具类库,除了jxl以外,poi包也是一个操作excel的类库。而对比两个包,jxl更适用与数据量大的情况,而poi在数据量不高(大约5000以内)时,效率较高,但占用内存大,更容易内存溢出。测试数据privateintid;privateStringn
flink核心特性
24k小善
flink 大数据 java 架构
ApacheFlink核心特性详解一、流处理与批处理的统一Flink的核心设计理念之一是将流处理和批处理统一在一个框架中。这种统一性使得Flink在处理实时数据和批量数据时具有高度的灵活性和一致性。1.流处理与批处理的统一计算引擎流处理作为批处理的特例:Flink将批处理视为有限流(FiniteStream),从而实现了流处理和批处理的统一。统一API:Flink提供了DataStream和Dat
6种MySQL高可用方案对比分析
m0_74823595
mysql adb android
大家好,我是V哥,关于MySQL高可用方案,在面试中频频出现,有同学在字节面试就遇到过,主要考察你在高可用项目中是如何应用的,V哥整理了6种方案,供你参考。V哥推荐:2024最适合入门的JAVA课程MySQL的高可用方案有多种,常见的包括以下几种:1.主从复制(Master-SlaveReplication)原理:主库进行写操作,数据通过异步或半同步复制到从库。可以通过从库进行读操作,实现读写分离
Markdown 到 PowerPoint 转换工具——md2pptx
伍盛普Silas
Markdown到PowerPoint转换工具——md2pptxmd2pptxMarkdownToPowerPointconverter项目地址:https://gitcode.com/gh_mirrors/md/md2pptxmd2pptx是一个开源项目,它可以将Markdown格式的文本转换为PowerPoint演示文稿。该项目主要使用Python编程语言实现。项目基础介绍md2pptx是一个
Python网络爬虫-WebSocket数据抓取
程序小勇
faiss 爬虫 python 网络协议 websocket 开发语言
目录前言1、WebSocket请求的分析通常涉及以下几个方面:2、利用WebSocket爬取数据总结最后,创作不易!非常感谢大家的关注、点赞、评论啦!谢谢三连哦!好人好运连连,学习进步!工作顺利哦!博主介绍:✌专注于前后端、机器学习、人工智能应用领域开发的优质创作者、秉着互联网精神开源贡献精神,答疑解惑、坚持优质作品共享。本人是掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战,
设计模式 笔记10 | 适配器模式 在源码中的应用 | Spring源码的 AOP 注册中心存储了不同的适配器实现 | SpringMVC源码doDisPatch方法里的 HandlerAdapter
「已注销」
设计模式 设计模式 适配器模式 spring
文章目录一、适配器模式知识回顾二、类适配器使用案例之拓展登陆业务2.1模拟登陆的旧系统2.2旧系统拓展【类适配器】2.3旧系统拓展【接口适配器】三、适配器模式在Spring源码中的应用四、SpringMVC中的适配器模式五、总结参考资料一、适配器模式知识回顾适配器定义:将一个类的接口转换成另一种目标接口,使得原本由于接口不兼容而不能一起工作的类能一起工作适配器分类:类结构型模式(耦合读较高)和对象
Pytorch实现论文之一种基于扰动卷积层和梯度归一化的生成对抗网络
这张生成的图像能检测吗
GAN系列 优质GAN模型训练自己的数据集 pytorch 人工智能 机器学习 生成对抗网络 神经网络 计算机视觉 深度学习
简介简介:提出了一种针对鉴别器的梯度惩罚方法和在鉴别器中采用扰动卷积,拟解决锐梯度空间引起的训练不稳定性问题和判别器的记忆问题。论文题目:APerturbedConvolutionalLayerandGradientNormalizationbasedGenerativeAdversarialNetwork(一种基于扰动卷积层和梯度归一化的生成对抗网络)会议:20244thInternationa
Pytorch实现之在LSGAN中结合重建损失
这张生成的图像能检测吗
GAN系列 优质GAN模型训练自己的数据集 pytorch 人工智能 python
简介简介:这篇论文在LSGAN的基础上结合了重建损失来产生通过传统不良数据检测(BDD)机制的人工测量。这篇博客的主要内容是关于实现了重建损失与LSGAN的结合。论文题目:FalseDataInjectionAttacksBasedonLeastSquaresGenerativeAdversarialNetworkswithReconstructionLoss(基于重构损失最小二乘生成对抗网络的虚
Pytorch实现论文:利用推土机距离与梯度惩罚在ACGAN中训练。
这张生成的图像能检测吗
优质GAN模型训练自己的数据集 pytorch 人工智能 深度学习 gan 机器学习 生成对抗网络
论文简介论文:ACWGAN-GPformillingtoolbreakagemonitoringwithimbalanceddata(ACWGAN-GP用于铣削工具断裂监视的数据不平衡数据)出处:RoboticsandComputer-IntegratedManufacturing论文摘要:铣削操作过程中的刀具破损监测(TBM)对于确保工件质量和最大限度减少经济损失至关重要。在训练数据充足、分布均
设计模式之适配模式是什么?以及在Spring AOP中的拦截器链的使用源码解析。
一个儒雅随和的男子
设计模式 spring 设计模式 spring java
前言 本文涉及到适配模式的基本用法,以及在SpringAOP中如何使用,首先需要了解适配模式的工作原理,然后结合SpringAOP的具体实现来详细详细解析源码。 首先,适配模式,也就是AdapterPattern,属于结构型设计模式,主要用于让不兼容的接口能够一起工作。要了解它的定义、结构、应用场景以及优缺点。然后,可能需要一个具体的例子来说明,比如电压适配器,这样用户更容易理解。 接下来是
Pytorch实现论文之三元DCGAN生成RGB图像用于红外图像着色生成
这张生成的图像能检测吗
GAN系列 优质GAN模型训练自己的数据集 人工智能 python 生成对抗网络 深度学习 pytorch 机器学习 计算机视觉
简介简介:采用了三次DCGAN单独生成单通道图像之后进行组成RGB图像放入鉴别器中检测,并在鉴别器和生成器的损失训练中采用梯度方法来提升或者降低权重。该方法将用于获得红外图像着色的生成。论文题目:InfraredImageColorizationbasedonaTripletDCGANArchitecture(基于三元DCGAN架构的红外图像着色)会议:2017IEEEConferenceonCo
springcloudalibaba组件gateway
zzyh123456
gateway 前端 javascript
SpringCloudAlibaba组件中的Gateway是一个基于SpringCloudGateway实现的API网关,它专为微服务架构提供简单且有效的API路由管理方式。以下是对SpringCloudAlibabaGateway的详细介绍:一、基本概念API网关:作为系统的统一入口,提供内部服务的路由中转,为客户端提供统一服务。网关可以处理一些与业务本身功能无关的公共逻辑,如认证、鉴权、监控、
springcloud的组件及作用
zzyh123456
spring cloud spring 后端
SpringCloud是一个用于构建分布式系统的工具集,它提供了一系列组件来简化微服务架构的开发和部署。以下是一些关键的SpringCloud组件及其作用:1.服务注册与发现Eureka:Eureka是SpringCloud中的核心组件之一,用于实现服务注册与发现。服务实例通过EurekaServer进行注册,消费者通过EurekaServer查询服务实例的地址,实现服务的自动发现和调用。Eure
微服务架构中的负载均衡与服务注册中心(Nacos)
ღ᭄ꦿ࿐Never say never꧂
微服务 架构 微服务 负载均衡 spring cloud spring boot 后端 java
1.负载均衡:解决实际业务问题1.1业务场景思考想象一个电子商务平台的微服务架构。我们有一个订单服务和多个用户服务实例。当订单服务需要调用用户服务时,它如何选择具体调用哪一台用户服务器?这就是负载均衡要解决的核心问题。1.2常用负载均衡算法及其业务影响1.2.1轮询(RoundRobin)原理:请求依次分配给每个服务器。业务影响:优点:实现简单,在服务器性能相近的情况下能达到较好的负载平衡。缺点:
【微服务】Nacos Discovery--服务治理
SoftwareDevOps
微服务 分布式 Nacos 微服务注册中心 服务治理
NacosDiscovery--服务治理前言服务治理常见的注册中心ZookeeperEurekaConsulNacosNacos入门搭建nacos环境将商品微服务注册到nacos将订单微服务注册到nacos总结前言上一章中,我们利用用户–订单–商品,实现了三个简单的微服务,实现了微服务之间的调用。但不知道大家有没有发现,我们是通过硬编码的方式,把服务者,消费者的服务Url,写到了代码中,这样做肯定
Linux下JVM相关指令详解及案例介绍
码农阿豪@新空间
好“物”分享 linux jvm 运维
个人名片作者简介:java领域优质创作者个人主页:码农阿豪工作室:新空间代码工作室(提供各种软件服务)个人邮箱:[
[email protected] ]个人微信:15279484656个人导航网站:www.forff.top座右铭:总有人要赢。为什么不能是我呢?专栏导航:码农阿豪系列专栏导航面试专栏:收集了java相关高频面试题,面试实战总结️Spring5系列专栏:整理了Spring5重要知识点与
Redis 集群模式的工作原理能说一下么?
小新杂谈社
缓存 后端面试 redis 数据库 缓存 分布式
面试题Redis集群模式的工作原理能说一下么?在集群模式下,Redis的key是如何寻址的?分布式寻址都有哪些算法?了解一致性hash算法吗?面试官心理分析在前几年,Redis如果要搞几个节点,每个节点存储一部分的数据,得借助一些中间件来实现,比如说有codis,或者twemproxy,都有。有一些Redis中间件,你读写Redis中间件,Redis中间件负责将你的数据分布式存储在多台机器上的Re
ffmpeg实现视频拼接,图片生成视频demo
德玛西亚没有明天
ffmpeg 音视频
利用ffmpeg实现图片生成视频,视频拼接,添加字幕等$img){//添加背景//$returnImg="backImg{$key}.jpg";//$output="output{$key}.mp4";//$returnImg=$this->addBack($img,$returnImg);$output="output0.mp4";$returnImg="backImg0.jpg";$time=
RPC(3)--基于 Nacos 的服务发现与负载均衡版
三喂树屋
Java rpc 服务发现 负载均衡
nacos:提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。Nacos是构建以“服务”为中心的现代应用架构(例如微服务范式、云原生范式)的服务基础设施。nacos架构如下(图片来源)依赖包:com.alibaba.nacosnacos-client1.3.0使用如下://创建命名服务NamingServicenamingService=NamingFacto
哈希表总结-C语言版
vanguard2021
Leetcode刷题 哈希表
目录1、哈希表的原理2、自己实现的hash表--C语言版3、C语言开源项目uthash.h中的hash接口使用指南3.1uthash.h头文件说明3.2常见的uthash.h接口以及使用方法4、实践应用参考资料:1、哈希表的原理哈希表的关键思想是使用哈希函数将键映射到存储桶。更确切地说,当我们插入一个新的键时,哈希函数将决定该键应该分配到哪个桶中,并将该键存储在相应的桶中;当我们想要搜索一个键时,
【虚拟仿真】Unity3D中如何实现让3D模型显示在UI前面
恬静的小魔龙
# Unity3D VR/AR开发 unity 3d ui
推荐阅读CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客QQ群:1040082875大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。一、前言最近有小伙伴在群里问我,如何将3D模型显示在UI前面,比如这样:
微服务网关springcloud gateway整合nacos实现服务名负载均衡
程序猿20
开发框架 微服务 gateway 负载均衡 nacos
1.添加依赖com.alibaba.cloudspring-cloud-starter-alibaba-nacos-discovery2.2.5.RELEASE2.添加配置spring:cloud:nacos:discovery:#服务注册地址server-addr:192.168.17.94:88483.将路由配置中的uri采用lb://服务名的形式进行配置spring:cloud:gatewa
NACOS保姆笔记(2)——Spring Cloud Alibaba Nacos服务注册与发现以及负载均衡
laolitou_1024
Nacos 微服务 中间件 服务发现 微服务 rpc 中间件 spring cloud
前面我们介绍过:NACOS保姆笔记(1)——NACOS的安装和启动本篇主要介绍下Nacos和springcloudalibaba来组合实现服务注册与发现以及负载均衡。环境具体的版本约束参见版本说明,我的环境版本如下:Nacos:2.2.0Springboot:2.6.13SpringCloudAlibaba:2021.0.5.0Loadbalancer:3.1.0Nacos端1,可以新建一个nam
数据权限校验实践
fengdongnan
数据库 前端 网络
数据权限控制实践最近在实习中为公司项目完成一个文件数据权限校验代码的转换重构,写这篇博客来记录前后两种权限校验的实现方案与相关概念原实现方案:RBAC-基于角色的访问控制RBAC(Role-BasedAccessControl)RBAC是一种常见的访问控制模型,它通过角色来分配权限。在RBAC模型中,角色是一组权限的集合,用户通过被分配角色来获得相应的权限。RBAC的主要特点包括:角色分配:用户被
[黑洞与暗粒子]没有光的世界
comsci
无论是相对论还是其它现代物理学,都显然有个缺陷,那就是必须有光才能够计算
但是,我相信,在我们的世界和宇宙平面中,肯定存在没有光的世界....
那么,在没有光的世界,光子和其它粒子的规律无法被应用和考察,那么以光速为核心的
&nbs
jQuery Lazy Load 图片延迟加载
aijuans
jquery
基于 jQuery 的图片延迟加载插件,在用户滚动页面到图片之后才进行加载。
对于有较多的图片的网页,使用图片延迟加载,能有效的提高页面加载速度。
版本:
jQuery v1.4.4+
jQuery Lazy Load v1.7.2
注意事项:
需要真正实现图片延迟加载,必须将真实图片地址写在 data-original 属性中。若 src
使用Jodd的优点
Kai_Ge
jodd
1. 简化和统一 controller ,抛弃 extends SimpleFormController ,统一使用 implements Controller 的方式。
2. 简化 JSP 页面的 bind, 不需要一个字段一个字段的绑定。
3. 对 bean 没有任何要求,可以使用任意的 bean 做为 formBean。
使用方法简介
jpa Query转hibernate Query
120153216
Hibernate
public List<Map> getMapList(String hql,
Map map) {
org.hibernate.Query jpaQuery = entityManager.createQuery(hql);
if (null != map) {
for (String parameter : map.keySet()) {
jp
Django_Python3添加MySQL/MariaDB支持
2002wmj
mariaDB
现状
首先,
[email protected] 中默认的引擎为 django.db.backends.mysql 。但是在Python3中如果这样写的话,会发现 django.db.backends.mysql 依赖 MySQLdb[5] ,而 MySQLdb 又不兼容 Python3 于是要找一种新的方式来继续使用MySQL。 MySQL官方的方案
首先据MySQL文档[3]说,自从MySQL
在SQLSERVER中查找消耗IO最多的SQL
357029540
SQL Server
返回做IO数目最多的50条语句以及它们的执行计划。
select top 50
(total_logical_reads/execution_count) as avg_logical_reads,
(total_logical_writes/execution_count) as avg_logical_writes,
(tot
spring UnChecked 异常 官方定义!
7454103
spring
如果你接触过spring的 事物管理!那么你必须明白 spring的 非捕获异常! 即 unchecked 异常! 因为 spring 默认这类异常事物自动回滚!!
public static boolean isCheckedException(Throwable ex)
{
return !(ex instanceof RuntimeExcep
mongoDB 入门指南、示例
adminjun
java mongodb 操作
一、准备工作
1、 下载mongoDB
下载地址:http://www.mongodb.org/downloads
选择合适你的版本
相关文档:http://www.mongodb.org/display/DOCS/Tutorial
2、 安装mongoDB
A、 不解压模式:
将下载下来的mongoDB-xxx.zip打开,找到bin目录,运行mongod.exe就可以启动服务,默
CUDA 5 Release Candidate Now Available
aijuans
CUDA
The CUDA 5 Release Candidate is now available at http://developer.nvidia.com/<wbr></wbr>cuda/cuda-pre-production. Now applicable to a broader set of algorithms, CUDA 5 has advanced fe
Essential Studio for WinRT网格控件测评
Axiba
JavaScript html5
Essential Studio for WinRT界面控件包含了商业平板应用程序开发中所需的所有控件,如市场上运行速度最快的grid 和chart、地图、RDL报表查看器、丰富的文本查看器及图表等等。同时,该控件还包含了一组独特的库,用于从WinRT应用程序中生成Excel、Word以及PDF格式的文件。此文将对其另外一个强大的控件——网格控件进行专门的测评详述。
网格控件功能
1、
java 获取windows系统安装的证书或证书链
bewithme
windows
有时需要获取windows系统安装的证书或证书链,比如说你要通过证书来创建java的密钥库 。
有关证书链的解释可以查看此处 。
public static void main(String[] args) {
SunMSCAPI providerMSCAPI = new SunMSCAPI();
S
NoSQL数据库之Redis数据库管理(set类型和zset类型)
bijian1013
redis 数据库 NoSQL
4.sets类型
Set是集合,它是string类型的无序集合。set是通过hash table实现的,添加、删除和查找的复杂度都是O(1)。对集合我们可以取并集、交集、差集。通过这些操作我们可以实现sns中的好友推荐和blog的tag功能。
sadd:向名称为key的set中添加元
异常捕获何时用Exception,何时用Throwable
bingyingao
用Exception的情况
try {
//可能发生空指针、数组溢出等异常
} catch (Exception e) {
 
【Kafka四】Kakfa伪分布式安装
bit1129
kafka
在http://bit1129.iteye.com/blog/2174791一文中,实现了单Kafka服务器的安装,在Kafka中,每个Kafka服务器称为一个broker。本文简单介绍下,在单机环境下Kafka的伪分布式安装和测试验证 1. 安装步骤
Kafka伪分布式安装的思路跟Zookeeper的伪分布式安装思路完全一样,不过比Zookeeper稍微简单些(不
Project Euler
bookjovi
haskell
Project Euler是个数学问题求解网站,网站设计的很有意思,有很多problem,在未提交正确答案前不能查看problem的overview,也不能查看关于problem的discussion thread,只能看到现在problem已经被多少人解决了,人数越多往往代表问题越容易。
看看problem 1吧:
Add all the natural num
Java-Collections Framework学习与总结-ArrayDeque
BrokenDreams
Collections
表、栈和队列是三种基本的数据结构,前面总结的ArrayList和LinkedList可以作为任意一种数据结构来使用,当然由于实现方式的不同,操作的效率也会不同。
这篇要看一下java.util.ArrayDeque。从命名上看
读《研磨设计模式》-代码笔记-装饰模式-Decorator
bylijinnan
java 设计模式
声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.Fi
Maven学习(一)
chenyu19891124
Maven私服
学习一门技术和工具总得花费一段时间,5月底6月初自己学习了一些工具,maven+Hudson+nexus的搭建,对于maven以前只是听说,顺便再自己的电脑上搭建了一个maven环境,但是完全不了解maven这一强大的构建工具,还有ant也是一个构建工具,但ant就没有maven那么的简单方便,其实简单点说maven是一个运用命令行就能完成构建,测试,打包,发布一系列功
[原创]JWFD工作流引擎设计----节点匹配搜索算法(用于初步解决条件异步汇聚问题) 补充
comsci
算法 工作 PHP 搜索引擎 嵌入式
本文主要介绍在JWFD工作流引擎设计中遇到的一个实际问题的解决方案,请参考我的博文"带条件选择的并行汇聚路由问题"中图例A2描述的情况(http://comsci.iteye.com/blog/339756),我现在把我对图例A2的一个解决方案公布出来,请大家多指点
节点匹配搜索算法(用于解决标准对称流程图条件汇聚点运行控制参数的算法)
需要解决的问题:已知分支
Linux中用shell获取昨天、明天或多天前的日期
daizj
linux shell 上几年 昨天 获取上几个月
在Linux中可以通过date命令获取昨天、明天、上个月、下个月、上一年和下一年
# 获取昨天
date -d 'yesterday' # 或 date -d 'last day'
# 获取明天
date -d 'tomorrow' # 或 date -d 'next day'
# 获取上个月
date -d 'last month'
#
我所理解的云计算
dongwei_6688
云计算
在刚开始接触到一个概念时,人们往往都会去探寻这个概念的含义,以达到对其有一个感性的认知,在Wikipedia上关于“云计算”是这么定义的,它说:
Cloud computing is a phrase used to describe a variety of computing co
YII CMenu配置
dcj3sjt126com
yii
Adding id and class names to CMenu
We use the id and htmlOptions to accomplish this. Watch.
//in your view
$this->widget('zii.widgets.CMenu', array(
'id'=>'myMenu',
'items'=>$this-&g
设计模式之静态代理与动态代理
come_for_dream
设计模式
静态代理与动态代理
代理模式是java开发中用到的相对比较多的设计模式,其中的思想就是主业务和相关业务分离。所谓的代理设计就是指由一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理。比如我们在进行删除操作的时候需要检验一下用户是否登陆,我们可以删除看成主业务,而把检验用户是否登陆看成其相关业务
【转】理解Javascript 系列
gcc2ge
JavaScript
理解Javascript_13_执行模型详解
摘要: 在《理解Javascript_12_执行模型浅析》一文中,我们初步的了解了执行上下文与作用域的概念,那么这一篇将深入分析执行上下文的构建过程,了解执行上下文、函数对象、作用域三者之间的关系。函数执行环境简单的代码:当调用say方法时,第一步是创建其执行环境,在创建执行环境的过程中,会按照定义的先后顺序完成一系列操作:1.首先会创建一个
Subsets II
hcx2013
set
Given a collection of integers that might contain duplicates, nums, return all possible subsets.
Note:
Elements in a subset must be in non-descending order.
The solution set must not conta
Spring4.1新特性——Spring缓存框架增强
jinnianshilongnian
spring4
目录
Spring4.1新特性——综述
Spring4.1新特性——Spring核心部分及其他
Spring4.1新特性——Spring缓存框架增强
Spring4.1新特性——异步调用和事件机制的异常处理
Spring4.1新特性——数据库集成测试脚本初始化
Spring4.1新特性——Spring MVC增强
Spring4.1新特性——页面自动化测试框架Spring MVC T
shell嵌套expect执行命令
liyonghui160com
一直都想把expect的操作写到bash脚本里,这样就不用我再写两个脚本来执行了,搞了一下午终于有点小成就,给大家看看吧.
系统:centos 5.x
1.先安装expect
yum -y install expect
2.脚本内容:
cat auto_svn.sh
#!/bin/bash
Linux实用命令整理
pda158
linux
0. 基本命令 linux 基本命令整理
1. 压缩 解压 tar -zcvf a.tar.gz a #把a压缩成a.tar.gz tar -zxvf a.tar.gz #把a.tar.gz解压成a
2. vim小结 2.1 vim替换 :m,ns/word_1/word_2/gc  
独立开发人员通向成功的29个小贴士
shoothao
独立开发
概述:本文收集了关于独立开发人员通向成功需要注意的一些东西,对于具体的每个贴士的注解有兴趣的朋友可以查看下面标注的原文地址。
明白你从事独立开发的原因和目的。
保持坚持制定计划的好习惯。
万事开头难,第一份订单是关键。
培养多元化业务技能。
提供卓越的服务和品质。
谨小慎微。
营销是必备技能。
学会组织,有条理的工作才是最有效率的。
“独立
JAVA中堆栈和内存分配原理
uule
java
1、栈、堆
1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)3. 堆:存放所有new出来的对象。4. 静态域:存放静态成员(static定义的)5. 常量池:存放字符串常量和基本类型常量(public static f