<docs> 整理现有的两个Obsidian库得到的新库,后续的日志都基于这个库进行修改
parent
acc50a0f9c
commit
ff844de607
|
|
@ -0,0 +1 @@
|
|||
密码记录/
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "后端/极客时间Java实战/分布式服务/分布式服务容错.md",
|
||||
"file": "README.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
}
|
||||
|
|
@ -49,14 +49,14 @@
|
|||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "后端/极客时间Java实战/Netty/Netty 实现IM系统.md",
|
||||
"file": "开发中/本地版本的cos图床.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentTab": 3
|
||||
"currentTab": 2
|
||||
}
|
||||
],
|
||||
"direction": "vertical"
|
||||
|
|
@ -122,7 +122,7 @@
|
|||
"state": {
|
||||
"type": "backlink",
|
||||
"state": {
|
||||
"file": "后端/极客时间Java实战/Netty/Netty 实现IM系统.md",
|
||||
"file": "README.md",
|
||||
"collapseAll": false,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical",
|
||||
|
|
@ -139,7 +139,7 @@
|
|||
"state": {
|
||||
"type": "outgoing-link",
|
||||
"state": {
|
||||
"file": "后端/极客时间Java实战/Netty/Netty 实现IM系统.md",
|
||||
"file": "README.md",
|
||||
"linksCollapsed": false,
|
||||
"unlinkedCollapsed": true
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@
|
|||
"state": {
|
||||
"type": "outline",
|
||||
"state": {
|
||||
"file": "后端/极客时间Java实战/Netty/Netty 实现IM系统.md"
|
||||
"file": "README.md"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -183,30 +183,43 @@
|
|||
"command-palette:打开命令面板": false
|
||||
}
|
||||
},
|
||||
"active": "b0885c2694804173",
|
||||
"active": "fcca90a4313bff23",
|
||||
"lastOpenFiles": [
|
||||
"后端/极客时间Java实战/Netty/Netty 与 网络通信.md",
|
||||
"后端/极客时间Java实战/Netty/Netty 实现IM系统.md",
|
||||
"后端/极客时间Java实战/分布式服务/Zookeeper.md",
|
||||
"后端/极客时间Java实战/Netty",
|
||||
"后端/极客时间Java实战/分布式服务",
|
||||
"后端/极客时间Java实战/分布式服务/Dubbo服务端与客户端通信原理.md",
|
||||
"后端/极客时间Java实战/分布式服务/分布式服务容错.md",
|
||||
"后端/极客时间Java实战/分布式服务/Dubbo提供的各种服务引用机制.md",
|
||||
"未分类日志.md",
|
||||
"开发中/Vue3 + 腾讯COS文件上传.md",
|
||||
"工具相关文档/git/Git 笔记.md",
|
||||
"工具相关文档/git",
|
||||
"工具相关文档/未命名.md",
|
||||
"开发愿望清单.md",
|
||||
"日志检索.md",
|
||||
"后端/极客时间Java实战/分布式服务/Dubbo.md",
|
||||
"后端/极客时间Java实战/分布式服务/RPC.md",
|
||||
"后端/极客时间Java实战",
|
||||
"VSCode 连接 云服务器.md",
|
||||
"README.md",
|
||||
"web/现代WEB布局.md",
|
||||
"运维",
|
||||
"基础",
|
||||
"后端",
|
||||
"rust",
|
||||
"android",
|
||||
"web",
|
||||
"Welcome.md"
|
||||
"开发中/本地版本的cos图床.md",
|
||||
"工具相关文档/VSCode/VSCode 连接 云服务器.md",
|
||||
"工具相关文档/VSCode/VSCode 文件嵌套.md",
|
||||
"工具相关文档/VSCode",
|
||||
"未命名",
|
||||
"工具相关文档/Obsidian 使用笔记.md",
|
||||
"开发中/RayC后台开发日志.md",
|
||||
"gitea.md",
|
||||
"开发中",
|
||||
"未分类日志.md",
|
||||
"语言/Rust/Rust学习笔记一.md",
|
||||
"博客/Android/相机/Android Camera2 在预览时,录制视频.md",
|
||||
"博客/docker 安装 wordpress.md",
|
||||
"Bug日志/后端 -- Bug记录.md",
|
||||
"极客时间学习/Nginx_geek/核心基础.md",
|
||||
"语言/Kotlin/2023-11-16.md",
|
||||
"语言/未命名.md",
|
||||
"语言/Kotlin",
|
||||
"语言",
|
||||
"极客时间学习/Java 实战训练营/分布式服务/分布式服务.md",
|
||||
"极客时间学习/Java 实战训练营/分布式服务/分布式服务容错.md",
|
||||
"文档编写/PRD",
|
||||
"文档编写/PRD.md",
|
||||
"文档编写",
|
||||
"工具相关文档",
|
||||
"UI学习/PS 学习/日志.md",
|
||||
"web/js/`JS` `setTimeout` 和 `clearTimeout`.md",
|
||||
"web/css",
|
||||
"开发资源/SpotifyMusic.md",
|
||||
"文档编写/PRD/PRD 学习.md"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
```log
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
## nginx 在https的server中访问http 的链接会失败
|
||||
当我们有一个申请了 `https` 证书的 `server` 时,如果这个 `server` 中的服务使用到了一个 `http` 的链接,会访问失败,例如: 我在一个 `vue` 的项目中室友了 `http` 的链接时,访问会失败
|
||||
|
||||
- 解决办法
|
||||
- 网上的解决方案好像都是对于nginx做代理的后端资源的解决方案,是在server当中添加一个响应头的配置,但我的是访问的同一个nginx下不同服务的资源,目前这种方案没有尝试过
|
||||
- 对使用 `http` 的 `server` 申请一个 `https` 的证书, 我使用的是 `certbot` 为 `nginx` 中指定的server 的域名申请证书
|
||||
```
|
||||
sudo certbot --nginx --nginx-server=/nginx_config_path -d the_domain_which_need_https
|
||||
```
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
最近学习vbenjs 发现的一个内存缓存中使用到的,具体的要参考vben的cache代码,这里只简单记录一下两个的使用办法,
|
||||
`setTimeout` 其实是用来设置延时任务的函数,主要作用是在一段时间之后执行任务,会返回一个id,用来区分不同的任务
|
||||
```ts
|
||||
const timeoutId = setTimeout(() => {}, expire)
|
||||
```
|
||||
`clearTimeout` 用来清除使用setTimeout创建的延时任务,
|
||||
```typescript
|
||||
clearTimeout(timeoutId)
|
||||
```
|
||||
|
|
@ -0,0 +1,355 @@
|
|||
|
||||
>写在前面:
|
||||
> 1. 本文中的方法只是实现在 `Android` 中使用 `Camera2` 的情况下,实现一个在预览时,实现时评录制。本文中的代码只是一个demo,相机相关的流程需要再细化,
|
||||
> 2. 另外,本文中的代码会存在一个问题,预览过程中会出现拉伸,原因是,本例中使用的是全局预览,需要再做适配,后面再补上.
|
||||
> 3. 本文中的代码,并不规范,只是实现效果,许多地方的异常可能发生的地方,被直接忽略了
|
||||
|
||||
### 因为代码比较简单,所以直接给出代码:
|
||||
```kotlin
|
||||
class RecordVideoWhilePreviewClient(
|
||||
val context: Context,
|
||||
val mTextureView: AutoFitTextureView,
|
||||
val filePath: String,
|
||||
val stateListener: CameraStateListener
|
||||
) {
|
||||
companion object {
|
||||
const val TAG = "RecordVideoWhilePreviewClient"
|
||||
}
|
||||
private var state: State = State.NEW
|
||||
|
||||
val SENSOR_ORIENTATION_DEFAULT_DEGREES = 90
|
||||
private val SENSOR_ORIENTATION_INVERSE_DEGREES = 270
|
||||
private val DEAULT_ORIENTATIONS = SparseIntArray().apply {
|
||||
append(Surface.ROTATION_0, 90)
|
||||
append(Surface.ROTATION_90, 0)
|
||||
append(Surface.ROTATION_180, 270)
|
||||
append(Surface.ROTATION_270, 180)
|
||||
}
|
||||
private val INVERSE_ORIENTATIONS = SparseIntArray().apply {
|
||||
append(Surface.ROTATION_0, 270)
|
||||
append(Surface.ROTATION_90, 180)
|
||||
append(Surface.ROTATION_180, 90)
|
||||
append(Surface.ROTATION_270, 0)
|
||||
}
|
||||
|
||||
private var mBackgroundThread: HandlerThread = HandlerThread(TAG)
|
||||
private lateinit var mBackHandler: Handler
|
||||
@Volatile
|
||||
private var mCameraDevice: CameraDevice? = null
|
||||
@Volatile
|
||||
private var mCameraCaptureSession: CameraCaptureSession? = null
|
||||
@Volatile
|
||||
private var mCaptureRequest: CaptureRequest.Builder? = null
|
||||
@Volatile
|
||||
private var mPreviewSurface: Surface? = null
|
||||
@Volatile
|
||||
private var mRecordSurface: Surface? = null
|
||||
@Volatile
|
||||
private var mMediaRecorder: MediaRecorder? = null
|
||||
|
||||
@Volatile
|
||||
private var mSensorOrientation: Int = 0
|
||||
@Volatile
|
||||
private var mCameraOpenCloseLock = Semaphore(1)
|
||||
private lateinit var mPreviewSize: Size
|
||||
private lateinit var mVideoSize: Size
|
||||
|
||||
private val mSurfaceTextureListener = object : TextureView.SurfaceTextureListener {
|
||||
override fun onSurfaceTextureAvailable(texture: SurfaceTexture, width: Int, height: Int) {
|
||||
openCamera(width, height)
|
||||
}
|
||||
|
||||
override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int) {
|
||||
configureTransform(width, height)
|
||||
}
|
||||
|
||||
override fun onSurfaceTextureDestroyed(texture: SurfaceTexture) = true
|
||||
|
||||
override fun onSurfaceTextureUpdated(texture: SurfaceTexture) {
|
||||
} }
|
||||
|
||||
private val mCameraStateCallback = object : CameraDevice.StateCallback() {
|
||||
override fun onOpened(device: CameraDevice) {
|
||||
mCameraOpenCloseLock.release()
|
||||
mCameraDevice = device
|
||||
|
||||
if (!mTextureView.isAvailable) return
|
||||
|
||||
try {
|
||||
val texture = mTextureView.surfaceTexture!!
|
||||
// texture.setDefaultBufferSize(, 720)
|
||||
val previewSurface = Surface(texture)
|
||||
mPreviewSurface = previewSurface
|
||||
|
||||
setupMediaRecorder(1280, 720)
|
||||
val recordSurface = mRecordSurface!!
|
||||
|
||||
mCaptureRequest = device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW).apply {
|
||||
addTarget(previewSurface)
|
||||
addTarget(recordSurface)
|
||||
}
|
||||
|
||||
mCameraDevice?.createCaptureSession(
|
||||
listOf(previewSurface, recordSurface),
|
||||
mCaptureSessionStateCallback,
|
||||
mBackHandler
|
||||
)
|
||||
} catch (e: CameraAccessException) {
|
||||
Log.e(TAG, "onOpened: ")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onDisconnected(device: CameraDevice) {
|
||||
mCameraOpenCloseLock.release()
|
||||
device.close()
|
||||
mCameraDevice = null
|
||||
}
|
||||
|
||||
override fun onError(device: CameraDevice, error: Int) {
|
||||
mCameraOpenCloseLock.release()
|
||||
device.close()
|
||||
mCameraDevice = null
|
||||
}
|
||||
}
|
||||
|
||||
private val mCaptureSessionStateCallback = object : CameraCaptureSession.StateCallback() {
|
||||
override fun onConfigured(session: CameraCaptureSession) {
|
||||
mCameraCaptureSession = session
|
||||
|
||||
val camera = mCameraDevice ?: return
|
||||
val previewSurface = mPreviewSurface ?: return
|
||||
val recordSurface = mRecordSurface ?: return
|
||||
|
||||
val captureRequest = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW).apply {
|
||||
addTarget(previewSurface)
|
||||
addTarget(recordSurface)
|
||||
}
|
||||
mCaptureRequest = captureRequest
|
||||
session.setRepeatingRequest(captureRequest.build(), mCaptureCallback, mBackHandler)
|
||||
}
|
||||
|
||||
override fun onConfigureFailed(session: CameraCaptureSession) {
|
||||
Log.e(TAG, "CameraCaptureSession.StateCallback -- onConfigureFailed: ")
|
||||
}
|
||||
}
|
||||
|
||||
private val mCaptureCallback = object : CameraCaptureSession.CaptureCallback() {
|
||||
override fun onCaptureCompleted(
|
||||
session: CameraCaptureSession,
|
||||
request: CaptureRequest,
|
||||
result: TotalCaptureResult
|
||||
) {
|
||||
super.onCaptureCompleted(session, request, result)
|
||||
if (state == State.INITIALIZING) {
|
||||
onStateChange(State.READY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
mBackgroundThread.start()
|
||||
mBackHandler = Handler(mBackgroundThread.looper)
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
fun openCamera(width: Int, height: Int) {
|
||||
val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
||||
try {
|
||||
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
|
||||
throw RuntimeException("Time out waiting to lock camera opening")
|
||||
}
|
||||
val cameraId = manager.cameraIdList[0]
|
||||
val characteristics = manager.getCameraCharacteristics(cameraId)
|
||||
|
||||
val range21 = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
|
||||
|
||||
val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
|
||||
?: throw RuntimeException("Cannot get available preview/video sizes")
|
||||
|
||||
mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)!!
|
||||
|
||||
|
||||
mVideoSize = Size(1280, 720)
|
||||
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture::class.java), width, height, Size(2400, 1080));
|
||||
|
||||
mTextureView.setAspectRatio(mPreviewSize.width, mPreviewSize.height)
|
||||
configureTransform(width, height)
|
||||
mMediaRecorder = MediaRecorder()
|
||||
manager.openCamera(cameraId, mCameraStateCallback, null)
|
||||
} catch (e: CameraAccessException) {
|
||||
Log.e(RecordVideoWhilePreview.TAG, "openCamera: Cannot access the camera. \n$e")
|
||||
} catch (e: NullPointerException) {
|
||||
Log.e(RecordVideoWhilePreview.TAG, "onRequestPermissionsResult: 没得相机硬件")
|
||||
} catch (e: InterruptedException) {
|
||||
throw RuntimeException("Interrupted while trying to lock camera opening.")
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupMediaRecorder(width: Int, height: Int) {
|
||||
var mediaRecorder = mMediaRecorder
|
||||
if (mMediaRecorder == null) {
|
||||
mediaRecorder = MediaRecorder()
|
||||
} else {
|
||||
mediaRecorder?.reset()
|
||||
}
|
||||
|
||||
val rotation = (context as Activity).windowManager.defaultDisplay.rotation
|
||||
when (mSensorOrientation) {
|
||||
SENSOR_ORIENTATION_DEFAULT_DEGREES -> {
|
||||
mediaRecorder?.setOrientationHint(DEAULT_ORIENTATIONS.get(rotation))
|
||||
}
|
||||
SENSOR_ORIENTATION_INVERSE_DEGREES -> {
|
||||
mediaRecorder?.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation))
|
||||
}
|
||||
}
|
||||
|
||||
var recordSurface = mRecordSurface
|
||||
if (recordSurface == null) {
|
||||
recordSurface = MediaCodec.createPersistentInputSurface()
|
||||
mRecordSurface = recordSurface
|
||||
}
|
||||
|
||||
mediaRecorder?.apply {
|
||||
setInputSurface(recordSurface!!)
|
||||
|
||||
setVideoSource(MediaRecorder.VideoSource.SURFACE)
|
||||
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
|
||||
|
||||
setOutputFile(filePath)
|
||||
|
||||
setVideoEncodingBitRate(1280*720)
|
||||
setVideoSize(width, height)
|
||||
setVideoEncoder(MediaRecorder.VideoEncoder.H264)
|
||||
|
||||
setCaptureRate(30.0)
|
||||
setVideoFrameRate(30)
|
||||
|
||||
prepare()
|
||||
}
|
||||
|
||||
mMediaRecorder = mediaRecorder
|
||||
}
|
||||
|
||||
private fun chooseOptimalSize(
|
||||
choices: Array<Size>,
|
||||
width: Int,
|
||||
height: Int,
|
||||
aspectRatio: Size
|
||||
): Size {
|
||||
val w = aspectRatio.width
|
||||
val h = aspectRatio.height
|
||||
val bigEnough = choices.filter {
|
||||
it.height == it.width * h / w && it.width >= width && it.height >= height
|
||||
}
|
||||
return if (bigEnough.isNotEmpty()) {
|
||||
Collections.min(bigEnough, CompareSizeByArea())
|
||||
} else {
|
||||
choices[0]
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureTransform(viewWidth: Int, viewHeight: Int) {
|
||||
val rotation = (context as Activity).windowManager.defaultDisplay.rotation
|
||||
val matrix = Matrix()
|
||||
val viewRect = RectF(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat())
|
||||
val bufferRect = RectF(0f, 0f, mPreviewSize.height.toFloat(), mPreviewSize.width.toFloat())
|
||||
val centerY = viewRect.centerY()
|
||||
val centerX = viewRect.centerX()
|
||||
|
||||
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
|
||||
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY())
|
||||
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL)
|
||||
val scale = Math.max(
|
||||
viewHeight.toFloat() / mPreviewSize.height,
|
||||
viewWidth.toFloat() / mPreviewSize.width
|
||||
)
|
||||
with(matrix) {
|
||||
postScale(scale, scale, centerX, centerY)
|
||||
postRotate((90 * (rotation - 2)).toFloat(), centerX, centerY)
|
||||
}
|
||||
}
|
||||
mTextureView.setTransform(matrix)
|
||||
}
|
||||
|
||||
private fun onStateChange(newState: State) {
|
||||
state = newState
|
||||
stateListener.onStateChange(state)
|
||||
val state = when (state) {
|
||||
State.NEW -> "STATE.NEW"
|
||||
State.INITIALIZING -> "STATE.INITIALIZING"
|
||||
State.READY -> "STATE.READY"
|
||||
State.RECORDING -> "STATE.RECORDING"
|
||||
State.COMPETE -> "STATE.COMPLETE"
|
||||
}
|
||||
context.showToast(state, Toast.LENGTH_SHORT)
|
||||
}
|
||||
|
||||
fun initialize() {
|
||||
if (mTextureView.isAvailable) {
|
||||
openCamera(mTextureView.width, mTextureView.height)
|
||||
} else {
|
||||
mTextureView.surfaceTextureListener = mSurfaceTextureListener
|
||||
}
|
||||
onStateChange(State.INITIALIZING)
|
||||
}
|
||||
|
||||
fun close() {
|
||||
mBackgroundThread?.quitSafely()
|
||||
try {
|
||||
mBackgroundThread?.join()
|
||||
} catch (e: InterruptedException) {
|
||||
Log.e(TAG, "close: ")
|
||||
}
|
||||
mPreviewSurface?.release()
|
||||
mRecordSurface?.release()
|
||||
mMediaRecorder?.release()
|
||||
mMediaRecorder = null
|
||||
}
|
||||
|
||||
fun startRecord() {
|
||||
if (state != State.READY && state != State.COMPETE) return
|
||||
|
||||
context.showToast("开始录像", Toast.LENGTH_SHORT)
|
||||
setupMediaRecorder(1280, 720)
|
||||
mMediaRecorder?.let {
|
||||
it.start()
|
||||
}
|
||||
onStateChange(State.RECORDING)
|
||||
}
|
||||
|
||||
fun stopRecord() {
|
||||
if (state != State.RECORDING) return
|
||||
|
||||
context.showToast("结束录像", Toast.LENGTH_SHORT)
|
||||
mMediaRecorder?.let {
|
||||
it.stop()
|
||||
it.reset()
|
||||
}
|
||||
onStateChange(State.COMPETE)
|
||||
}
|
||||
|
||||
interface CameraStateListener {
|
||||
fun onStateChange(newState: State)
|
||||
}
|
||||
|
||||
enum class State {
|
||||
NEW,
|
||||
INITIALIZING,
|
||||
READY,
|
||||
RECORDING,
|
||||
COMPETE,
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### 需要注意的问题:
|
||||
- 在创建 `MediaRecorder` 的时候,需要设置文件路径,这个时候,会在文件系统中生成一个空文件,等到录制的视频数据写入。
|
||||
- 但是我们上面的代码中,在 `CameraDevice.StateCallback` 的 `onOpened()` 中床创建 `CameraCaptureSession.StateCallback` 后面的过程中需要使用到 用来在 `MediaRecorder` 的 `Surface`, 需要提前 `设置好MediaRecorder` 并调用 `prepare` 不然预览会失败
|
||||
- 所以在第一次会创建一个文件,建议处理好文件的路径,本例目前只有一个文件路径
|
||||
|
||||
### 直接总结:
|
||||
- 本文主要参考的是 [google官方的demo](https://github.com/android/camera-samples/tree/main/Camera2Basic), 官方的预览和录制视频是分开的,导致我一开始以为需要重新创建 `CameraCaptureSession`, 所以一开始,是在 *预览* 和 *视频录制* 之间进行切换,但是这个方法在 **切换** 的时候,会有明显的卡顿。
|
||||
- 最后选择了在预览的 `CameraCaptureSession` 中添加 `MediaRecorder` 用来录制的 `Surface`. 最后实现的效果还是相对理想的,但是会有一个瑕疵,预览的显示和最后录制得到的视频不一致,但是我需要的是最后的结果,屏幕预览的效果,后面再适配一下,是我可以接受的效果
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
- 使用 docker 运行一个 mysql, 可以自己再创建一个用户,授权之后,再提供给wordpress使用
|
||||
``` shell
|
||||
sudo docker pull mysql
|
||||
sudo docker run --name=mysql-wp -p 3306:3306 \
|
||||
-v /local/data/path:/var/lib/mysql \
|
||||
-e MYSQL_ROOT_PASSWORD=password \
|
||||
-d mysql
|
||||
```
|
||||
- 安装运行wordpress
|
||||
``` shell
|
||||
sudo docker pull wordpress
|
||||
sudo docker run --name wp -p 1080:80 \
|
||||
-e WORDPRESS_DB_HOST=mysql_tcp_link
|
||||
-e WORDPRESS_DB_USER=root
|
||||
-e WORDPRESS_DB_PASSWORD=password
|
||||
-d wordpress
|
||||
```
|
||||
- 访问服务器ip:1080端口,初始化wordpress。因为指定了数据库,成功的话会跳过数据的配置部分,后面的很简单,跟着提示完成即可
|
||||
- 安装主题,如果需要上传主题,需要修改wordpress的容器中的php的上传文件大小的配置
|
||||
```shell
|
||||
# 默认情况下的上传文件大小是 2M, 可以在 WordPress 的 `媒体->上传文件` 的最下方会显示文件上传限制
|
||||
sudo docker exec -it `wp_container_id` bash # 进入wordpress容器
|
||||
cp /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini #
|
||||
vim /usr/local/etc/php/php.ini
|
||||
# 修改一下几个配置
|
||||
# memory_limit 500M
|
||||
# upload_max_filesize=500M
|
||||
# post_max_size=500M
|
||||
```
|
||||
- 安装的主题是 [Sakurairo](https://github.com/mirai-mamori/Sakurairo)
|
||||
上传成功后可以自动安装,安装的时间不长,后面跟着[官方文档](https://docs.fuukei.org/first-step/theme-install/) 进行配置就可以了
|
||||
- `Nginx` 配置代理,配置之后,云服务器防火墙关闭1080端口使用域名进行访问,需要现在wordpress中吧域名相关的配置做修改
|
||||
```nginx
|
||||
server {
|
||||
server_name 域名;
|
||||
listen 80;
|
||||
|
||||
access_log logs/wp.access.log;
|
||||
error_log logs/wp.error.log;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:1080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Host $http_host;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
- https 配置 使用 certbot 引用let's encrypt 为网站申请证书,记得过期后再次申请
|
||||
```
|
||||
sudo certbot --nginx --nginx-server-root=`conf_path` -d 域名
|
||||
```
|
||||
|
|
@ -0,0 +1 @@
|
|||
- Socket通信系列
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
### kotlin 下载慢
|
||||
- 2023-11-27 -- 国内下载kotlin的速度巨慢
|
||||
- 解决办法:修改settings.gradle.kts , 添加aliyun的依赖源,下载时间还是不短,但比原本的快
|
||||
```kotlin
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven { url = uri("https://maven.aliyun.com/repository/gradle-plugin") }
|
||||
maven { url = uri("https://maven.aliyun.com/repository/spring-plugin") }
|
||||
maven { url = uri("https://maven.aliyun.com/repository/public") }
|
||||
maven { url = uri("https://maven.aliyun.com/repository/google") }
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
maven { url = uri("https://maven.aliyun.com/repository/gradle-plugin") }
|
||||
maven { url = uri("https://maven.aliyun.com/repository/spring-plugin") }
|
||||
maven { url = uri("https://maven.aliyun.com/repository/public") }
|
||||
maven { url = uri("https://maven.aliyun.com/repository/google") }
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
### Java 运行的问题
|
||||
1. 在运行时,发现不能识别 主类的加载,
|
||||
解决办法:
|
||||
- 方法一: 清除掉,`.vscode` 文件夹下的 `settings.json` 和 `lauch.json`, 退出重新加载,系统编译之后, 选择 `Fix and clean`, 之后再重新加载,问题就消失了,展示没找到其他的解决办法
|
||||
- 方法二: 在文件查看的侧边栏中,的Java Project菜单左侧,`...` 选择clean workspace,再重载一次项目,即可
|
||||
|
||||
### Vue + TS
|
||||
1. 无法找到包:
|
||||
- 问题描述:在Vue3 + TS 的环境中,`can not find modules` , 但是包是已经下载好依赖的
|
||||
- 解决办法:在`tsconfig.json` 中关闭js的strict
|
||||
```
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": false,
|
||||
"noImplicitThis": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
- 界面上方`title_bar` 移动到底部
|
||||
- 需要修改 activity_main.xml,在layout和layout-land
|
||||
- 主题显示区域的 marginTop 修改为 marginBottom
|
||||
- Menu也将 marginTop 修改为 marginBottom
|
||||
- titleBar 修改 marginBottom
|
||||
- 调整之后menu中唤起的 note_menu_popupwindow 和 measure_menu_popupwindow 需要把 `paddingTop` 修改为 `paddingBottom`
|
||||
- titlebar小工具只显示 相机和电量
|
||||
- 需要修改 `fragment_main_titlebar` 和 `fragment_main_titlebar_820` `820` 是用于横屏模式
|
||||
- 把 `<include layout="@layout/other_param_h" />` 的 `other_param_h` 的根节点,设置为`visibility="gone"`
|
||||
- 设置了上面的之后,相机图标会消失
|
||||
- 需要把相机显示的两个控件的设置为 `layout_width="40.0.dip"`
|
||||
- Menu + TitleBar 背景颜色修改
|
||||
- 背景颜色直接修改,Menu和TitleBar的背景颜色是分开的
|
||||
- TGC 只留下TGC一个选项
|
||||
- 在 `activity_auxiliaire_setting.xml` 的 `rg_shortcut_button` 中除了 `tgc` 之外全部都 `visibility="gone"`
|
||||
- Menu图标修改
|
||||
- 后期替换图片和xml文件
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
## 12/31/2023
|
||||
|
||||
1. 安装Docker
|
||||
2. 使用docker 安装mysql
|
||||
mysql: 配置启动
|
||||
```shell
|
||||
sudo docker run --name eacenic-mysql-v2 -e MYSQL_ROOT_PASSWORD=Eci85370978 -v /home/ecs-user/docker/mysql/data:/var/lib/mysql -p 3308:3306 -d mysql
|
||||
```
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
### 使用Git作为同步工具
|
||||
|
||||
- [使用教程]([Obsidian通过github实现同步(Obsidian Git) - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/657924375))
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
在VSCode 的 vscode/settings.json 文件中添加如下规则:
|
||||
```JSON
|
||||
{
|
||||
// 控制相关文件嵌套展示
|
||||
"explorer.fileNesting.enabled": true,
|
||||
// 默认不展开
|
||||
"explorer.fileNesting.expand": false,
|
||||
// 嵌套的具体规则
|
||||
"explorer.fileNesting.patterns": {
|
||||
"*.ts": "$(capture).test.ts, $(capture).test.tsx",
|
||||
"*.tsx": "$(capture).test.ts, $(capture).test.tsx",
|
||||
"*.env": "$(capture).env.*",
|
||||
"CHANGELOG.md": "CHANGELOG*",
|
||||
"package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitattributes,.gitignore,.gitpod.yml,CNAME,README*,.npmrc,.browserslistrc",
|
||||
".eslintrc.cjs": ".eslintignore,.prettierignore,.stylelintignore,.commitlintrc.*,.prettierrc.*,.stylelintrc.*"
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
- `git fetch`
|
||||
- `git fetch` 用来同步远程仓库和本地仓库中的git 信息,查看远程仓库的完整分支结构
|
||||
- `git fetch` 同步远程仓库的全部log信息
|
||||
- `git log origin`
|
||||
`git fetch` 只会同步完整分支结构,不会直接将分支内容进行合并,
|
||||
所以不推荐 `git pull`
|
||||
- `git push`
|
||||
- `git push origin` 将当前分支push到远程仓库
|
||||
- `git push origin dev:dev` 可用于提交本地的新分支到远程分支
|
||||
|
||||
### commit 规范
|
||||
- 基本格式
|
||||
`<type>(<scope>): subject`
|
||||
- 说明
|
||||
- type (必填)
|
||||
- feat -- 新功能
|
||||
- fix/to -- 修复bug
|
||||
- docs -- 文档
|
||||
- style -- 格式 (不影响代码)
|
||||
- refactor -- 重构(代码变动,没有修改功能,也不是修复bug)
|
||||
- perf -- (优化, 替身性能,提升交互体验)
|
||||
- test -- 增加测试
|
||||
- chore -- 构建过程或辅助工具的变动
|
||||
- revert -- 版本回退
|
||||
- merge -- 代码合并
|
||||
- sync 同步主线或分支的bug
|
||||
- scope(可选) : 说明commit影响的范围
|
||||
- subject (必填):commit 目的的简短描述
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
- 初始化项目 (2024--0-20)
|
||||
> Spring Boot: `spring-boot-dependencies:3.1.8`
|
||||
> druid: `druid-spring-boot-3-starter:1.2.21`
|
||||
> mysql-connector-java: `mysql-connector-java:8.0.33`
|
||||
> mybatis-plus: `mybatis-plus-boot-starter:3.5.5`
|
||||
> hutool: `hutool-all:5.8.25`
|
||||
> mapstruct: `mapstruct:1.5.5.Final mapstruct-jdk8:1.5.5.Final mapstruct-processor:1.5.5.Final`
|
||||
|
||||
|
||||
- 开发用户管理模块 (目标暂时没有完成)
|
||||
- 目标
|
||||
- 用户管理
|
||||
- 用户的创建和修改
|
||||
- 角色的增加和删除
|
||||
- 角色管理
|
||||
- 角色的创建和修改
|
||||
- 权限的增加和删除
|
||||
- 权限初始化时,写在数据库中 不可修改和变更,只允许被角色引用
|
||||
-
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
- 使用用户的永久密钥在用户管理中申请
|
||||
- ==开放cos的CORS==,设置CORS 操作范围,CORS 来源需要设置
|
||||
- 按照官方文档中即可上传成功
|
||||
- ==后面需要改进的地方==,创建SpringBoot COS 后台,用来生成临时密钥,通过临时密钥,事项文件上传
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
- 开通腾讯的COS服务
|
||||
- 创建Bucket
|
||||
- 为Bucket设置CORS配置
|
||||
- 根据官网的 `Javascript SDK` 完成文件的增删改查
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
- 个人网站搭建 (先使用WordPress) -- 后面再开发
|
||||
- 先实现用户管理和腾讯COS文件上传 图床设置到cos中
|
||||
- 结合 cos 实现图床 -- 桌面端可用(或者web端也可以)先实现web端
|
||||
- 记账app
|
||||
- 音乐app -- spotify-web-api-java 玩起来
|
||||
- python 做一个爬虫工具
|
||||
- python 用来处理表格,做自动化办公
|
||||
- 以下内容每天学习一点(知道其中三样)
|
||||
- rust
|
||||
- kotlin 协程
|
||||
- python
|
||||
- nodejs (vue/react/koa)
|
||||
- Java (Spring boot)
|
||||
- 数据库(Mysql/MongoDB/Redis)(后面根据进度学习PostgreSQL)
|
||||
- Android/SpringBoot/等周边框架
|
||||
- Electron
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
- clientID: `9c027f3e063a41949ae76e69f54bf6a8`
|
||||
- ClientSecret: `f43c5aad266d4acfbe3805738c117a2c`
|
||||
-
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
## PRD 要素
|
||||
- 命名编码
|
||||
- 版本历史
|
||||
- 引言
|
||||
- 需求概述
|
||||
- 功能性说明
|
||||
- 非功能性说明
|
||||
|
||||
---
|
||||
### 文档标识
|
||||
|
||||
- 文档命名形式和编码
|
||||
XX 产品V1.0PRD_V1
|
||||
V1.0 是产品编号, PRD_V1 的V1 是PRD版本号
|
||||
- 版本历史
|
||||
- 版本号: V1
|
||||
- 文档编号:V1.0
|
||||
- 文档密级:
|
||||
- 产品名:
|
||||
- 编写人:
|
||||
- 编写日期
|
||||
- 修订记录
|
||||
- 版本号:
|
||||
- 修订人
|
||||
- 修订日期
|
||||
- 修订描述
|
||||
- 目录 -- 使用软件生成
|
||||
---
|
||||
### 引言
|
||||
- 引言
|
||||
- 产品背景
|
||||
- 说明该产品的研发的背景、市场趋势、发展前景(搜集并陈述事实,解释信息和活动、预测功能)
|
||||
- 说明该铲平研发的目的、意义、里程碑式的建设(说明研发的优势)
|
||||
- 预期读者
|
||||
- 该文档的阅读对象: 开发、测试、UI、产品
|
||||
- 产品规划
|
||||
- 说明该产品每一阶段的迭代目标, 开发及UI初期要达到的效果
|
||||
- 名词解释
|
||||
- 对文档中会出现的比较新的名称进行解释
|
||||
- 该文档的参考资料
|
||||
|
||||
---
|
||||
### 实现PRD文档的几种工具
|
||||
|
||||
- word
|
||||
- 原型工具
|
||||
- xiaopiu
|
||||
- Axure
|
||||
- 墨刀
|
||||
- figma
|
||||
- 慕客
|
||||
|
||||
---
|
||||
### 需求描述
|
||||
|
||||
- 业务流程
|
||||
- 组织架构图 -- 包含的模块、和子功能
|
||||
- 流程图 -- 泳道图(着重关注有判断逻辑和复杂业务逻辑的程序)
|
||||
- 用户角色
|
||||
- 用户角色
|
||||
- 用户描述
|
||||
- 功能清单
|
||||
- 功能模块
|
||||
- 主要功能点
|
||||
- 优先级 决定开发的顺序
|
||||
- 运行环境
|
||||
- 软件运行环境 (浏览器、 操作系统)
|
||||
- 产品规划
|
||||
- 对PRD中要开发的内容,给出关键里程碑,例如:需求评审通过的时间、开发完成的时间、上线时间
|
||||
- 描述产品可能存在的风险、比如性能瓶颈、没有解决的问题,用户不当使用的风险等等
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 功能性需求说明
|
||||
- 简要说明:介绍此功能的用途,包括其来源或背景,能解决哪些问题
|
||||
- 场景描述,产品 在哪种情况下会被用户使用,就是用户场景模拟
|
||||
- 用户场景
|
||||
- 用户描述
|
||||
- 业务规则:
|
||||
- 产品在开发时都有相应的业务规则,需要将跪着清晰的描述出来,让开发、测试人员明白,避免产生歧义
|
||||
- 业务规则必须是完整的、准确的,易懂的。
|
||||
- 原型图 (涉及到页面交互的部分)
|
||||
- 前置条件:该需求实现依赖的前提条件。比如上传照片是,需要存有图像文件
|
||||
- 后置条件:操作引发的后续处理
|
||||
|
||||
---
|
||||
|
||||
### 非功能性需求
|
||||
|
||||
- 性能需求
|
||||
- 产品使用的并发性能、响应性能、安全性能、预期效果描述
|
||||
- 需求变更的计划
|
||||
- 运营需求
|
||||
- 产品上线后如何运营、目标受众是什么,建议的推广策略、问题反馈途径、风险监控、亮点宣传等等。以及与运营人员的协作方式
|
||||
- 风险分析: 针对可能出现的问题进行预判和预设解决方案
|
||||
|
||||
---
|
||||
|
||||
### 铲平设计原则
|
||||
- 不做高保真
|
||||
- 不写废话
|
||||
- 不重复
|
||||
- 把时间花在产品得核心驱动力上,减少对无用功的投入,降低单调重复的操作频次,才能保证高效产出有价值的牵引力
|
||||
47
日志检索.md
47
日志检索.md
|
|
@ -1,2 +1,49 @@
|
|||
## 2024-03-08
|
||||
[[VSCode 连接 云服务器]]
|
||||
|
||||
## 2024-01-08
|
||||
- 学习PS
|
||||
- 修改X6(eci 工作,逆向,未完成)
|
||||
|
||||
## 2024-01-11
|
||||
- [[腾讯 COS + CDN实现图床]]
|
||||
- [[腾讯 COS + Spring Boot 上传下载]]
|
||||
|
||||
## 2024-01-14
|
||||
- [[Vite + VUE3 + TS 配置ESLint + Prettier]]
|
||||
- [[vue3 + vite 中import path]]
|
||||
- [[vue3 + vite 不能使用 import.meta]]
|
||||
- [[box-sizing border-box 失效]]
|
||||
|
||||
## 2024-01-15
|
||||
- [[docker 安装 wordpress]]
|
||||
|
||||
## 2024-01-17
|
||||
- [[Rust学习笔记一]]
|
||||
|
||||
## 2024-01-19
|
||||
- [[Vue3 + 腾讯COS文件上传]]
|
||||
|
||||
## 2024-01-20
|
||||
- [[本地版本的cos图床]]
|
||||
|
||||
## 2024-02-20
|
||||
- [[`JS` `setTimeout` 和 `clearTimeout`]]
|
||||
- JS 的 Reflect(反射)
|
||||
- [[VSCode 文件嵌套]]
|
||||
|
||||
## 2024-04-01
|
||||
[ViewModel 深度分析](https://juejin.cn/post/7344571269555126335?utm_source=gold_browser_extension)
|
||||
|
||||
## 2024-04-01
|
||||
#### Git 出现错误
|
||||
> git bash报错fatal: detected dubious ownership in repository at的解决方法
|
||||
> 在Android Studio中使用commit时,遇到的错误
|
||||
> 原因:网上说,文件夹的所有者和当前用户不一致
|
||||
> 解决办法:git bash中执行
|
||||
> `git config --global --add safe.directory`
|
||||
|
||||
|
||||
## 2024-04-12
|
||||
> Android 中的Service是在app的主线程中进行执行的,如果在主线程中执行了耗时操作,可能导致ANR
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
## 分布式服务体系
|
||||
#### 单体系统的问题
|
||||
1. 业务扩展性 -- 任何业务的调整都需要发布整个系统
|
||||
2. 性能伸缩性 -- 动态扩容对单体系统而言效率低下
|
||||
3. 代码复杂度 -- 修改一处代码容易引发连锁问题
|
||||
|
||||
- ##### 系统扩展性
|
||||
当前系统的业务需求发生变化时,对现在的系统改动程度的一种控制能力。改动程度越大,扩展性越差
|
||||
- ##### 伸缩性
|
||||
伸缩性,对系统性能的一种控制能力。如果通过简单扩容就能确保系统的性能得到等比例的提升,就认为系统具备较好的伸缩性。
|
||||
#### 分布式系统
|
||||
将整个系统拆分成多个能够独立运行的服务,这些服务再物理机上是隔离的,相互之间基于网络进行通信和协调
|
||||
|
||||
#### 单体系统的拆分策略
|
||||
- 纵向拆分:根据业务内容进行拆分,每一个服务都是单独的业务
|
||||
- 横向拆分:粒度更细,复用和组合业务能力
|
||||
#### 分布式系统的固有特性
|
||||
- 网络传输的三态性 -- 成功、失败、超时
|
||||
- 请求的容错性 -- 调用链路上的异常扩散,雪崩效应
|
||||
- 系统的异构性 -- 多种不同的技术体系
|
||||
- 数据的一致性 -- 传统的事务机制无法生效 (什么是传统的事务机制)
|
||||
#### 分布式核心技术点
|
||||
- 可用 -- 降级、限流、集群和负载均衡
|
||||
- 扩展 -- SPI机制、异步消息
|
||||
- 性能 -- 异步化、资源重用
|
||||
- 治理 -- 服务注册与发现机制
|
||||
#### 分布式系统组成结构
|
||||
- 功能性组件
|
||||
- 网络通信
|
||||
- 序列化
|
||||
- 传输协议
|
||||
- 服务调用
|
||||
- 非功能性组件
|
||||
- 服务治理
|
||||
- 服务路由
|
||||
- 服务容错
|
||||
- 服务监控
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## RPC架构
|
||||
`remote process call`, 远程过程调用,分布式的基础
|
||||
分布式系统基本功能组件:
|
||||
- 网络通信
|
||||
- 序列化/反序列化
|
||||
- 传输协议
|
||||
- 服务调用
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
|
||||
### 进程结构
|
||||
|
||||
- 单进程结构
|
||||
- 多进程结构(默认配置-- 更适合工作环境):多线程情况下,一个线程(请求)引起的错误会影响整个进程,保证高可用性(一个请求失败后,不影响其他请求)
|
||||
- woker 进程
|
||||
- cache 进程
|
||||
> 1. master 进程
|
||||
> 2. work 进程
|
||||
> 3. Cache Manager
|
||||
> 4. Cache Loader
|
||||
> Master 进程用来管理work进程, work进程用来处理实际的请求,Cache Loader 用来加载缓存,Cache Manager 用来管理缓存
|
||||
> work进程需要使用cache进程
|
||||
> 在 配置work 进程数时,需要把work进程数配置到和CPU核心数一样,还要为每个work进程绑定核心, 提高work进程的处理的能力和稳定性。
|
||||
|
||||
### 进程管理 -- 信号
|
||||
#### Master 进程
|
||||
1. 监控 Worker 进程
|
||||
- CHLD -- worker 进程结束的时候会向master 发送 `CHLD` 信号,用来监听worker进程,在必要的时候拉起worker进程
|
||||
2. 管理 Worker 进程
|
||||
3. 接收信号
|
||||
- TERM, INT -- 理解停止
|
||||
- QUIT -- 不影响用户的情况下,停止
|
||||
- HUP -- 重载配置文件
|
||||
- USR1 -- 重新打开日志文件, 做日志文件的切割
|
||||
- USR2 --
|
||||
- WINCH
|
||||
> USR2 和 WINCH 只能通过进程号 直接向master进程发送,其他的可以使用nginx的命令行实现
|
||||
|
||||
#### Worker 进程 -- 通常不给worker进程发送信号
|
||||
1. 接收信号
|
||||
- TREM, INT
|
||||
- QUIT
|
||||
- USR1
|
||||
- WINCH
|
||||
|
||||
#### Nginx 命令行
|
||||
- reload: HUP
|
||||
- reopen: USR1
|
||||
- stop: TERM
|
||||
- quit: QUIT
|
||||
|
||||
|
||||
### reload 流程
|
||||
- 向master 发送 HUP 信号
|
||||
- master 检查配置文件语法正确性
|
||||
- master 打开新的监听端口
|
||||
- master 用 新的配置文件 启动新的worker进程
|
||||
- master 向老的worker子进程发送发动QUIT信号
|
||||
- 老的worker进程关闭监听句柄,处理完当前连接后结束进程(超时会被强制退出, 时间是由master进程决定的)
|
||||
|
||||
|
||||
### 热升级流程
|
||||
|
||||
|
||||
### worker进程优雅的结束
|
||||
1. 设置定时器 -- worker_shutdown_timeout
|
||||
2. 关闭监听句柄 -- 不再处理新的连接
|
||||
4. 关闭空闲连接 -- 从线程池中处理
|
||||
5. 在循环中等待全部连接关闭 (或者超时,被强制关闭)
|
||||
6. 退出进程
|
||||
|
||||
### 网络收发 与 Nginx 事件间的关系
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
项目基本环境
|
||||
> `vite@5.0.8`
|
||||
> `vue@3.3.11`
|
||||
> `typescript@5.2.2`
|
||||
> `eslint@8.56.0`
|
||||
> `prettier@3.2.2`
|
||||
- 创建项目
|
||||
```shell
|
||||
pnpm create vite@latest project-name -- --template vue-ts
|
||||
```
|
||||
- 配置 `ESLint`
|
||||
- 安装ESLint
|
||||
```shell
|
||||
pnpm add -D eslint
|
||||
```
|
||||
- 配置 ESLint
|
||||
```
|
||||
npx eslint --init
|
||||
```
|
||||
选择的时候,直接选就可以了,最后默认安装推荐依赖即可
|
||||
- 配置 Prettier
|
||||
- 安装
|
||||
```
|
||||
pnpm add -D prettier
|
||||
```
|
||||
然后添加 `.prettierc.json` 文件保存格式信息
|
||||
|
|
@ -0,0 +1 @@
|
|||
VSCode 的bug,关闭VSCode,然后重启就可以了
|
||||
|
|
@ -0,0 +1 @@
|
|||
需要安装 `@types/node` 的依赖
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
通过 `COS` 和 `CND` 实现一个基本的图床
|
||||
- 开通之后创建 `Bucket`
|
||||
- 开通`CDN` 创建域名,这里用的自己服务器的域名的二级域名(在腾讯注册的,直接用就行,其他的域名不清楚),一路默认配置,就可以直接用,
|
||||
- 设置了一个上线
|
||||
- 设置了智能压缩,但是没有生效
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
- 需要引入 `cos` 的 `SDK`
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.qcloud</groupId>
|
||||
<artifactId>cos_api</artifactId>
|
||||
<version>5.6.155</version>
|
||||
</dependency>
|
||||
```
|
||||
- 需要使用 `api` 的 的 `accessKey` 和 `secretKey` ,使用临时密钥失败,不知道是不是没申请对,一直是 `InvalidAccessKey`
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
## Bug:
|
||||
### Kotlin 在 做 val 声明的对象 作为参数传递时,对象内的属性的值如果被修改,则原有对象的值也会产生变化,反之亦然。
|
||||
### 今天遇到的问题时,
|
||||
- 我在`FragmentA` 中将 `ObjectA` 写入到 `FragmentA` 和 `FragmentB` 两个页面共享的 一个 `ViewModel` 中,
|
||||
- 然后修改原来在 `ObjectA` 的属性值,之后进入到 `FragmentB` 中 (这么做的原因是因为每一次进入`FragmentA` 都需要 `ObjectA` 的属性值得到更新,但是放在启动 `FragmentB` 之前就直接清除了,这么做,导致了,后面的问题)
|
||||
- 最后在 `FragmentB` 中获取到错误的值
|
||||
#### 解决办法:
|
||||
- 把 `val` 改成 `var`, 或者修改 `Object` 清除属性值的时间点,把清除操作放到进入`FragmentA` 开始运行时的回调当中
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
## 基础扫盲
|
||||
- 基本数据类型
|
||||
- 语法
|
||||
- 复合类型
|
||||
- 分支,流程控制(分支、循环)
|
||||
- 函数 + 模块
|
||||
- 测试
|
||||
|
||||
## 所有权 -- Rust 的地基
|
||||

|
||||
主要需要把握几个点
|
||||
- 变量的可变与不可变的区别
|
||||
- 变量的作用域
|
||||
- 变量对应的资源的所有权 所有权相关的 `Copy` 和 `Move` 两个概念,函数传参,如果不使用引用,会发生所有权转移,需要再函数最后交回所有权(不绝对)
|
||||
|
||||
|
||||

|
||||
需要把握的几个点:
|
||||
- 引用存在的意义
|
||||
- 可变引用和不可变引用
|
||||
- 可变借用和不可变借用的作用域冲突问题,借用的几个重要原则
|
||||
- 使用借用作为函数形参的
|
||||
Loading…
Reference in New Issue