android之TextView自由选择复制

文章目录

  • 前言
  • 一、效果图
  • 二、实现步骤
    • 1.OnSelectListener
    • 2.SelectionInfo类
    • 3.TextLayoutUtil类
    • 4.复制弹框的xml布局
    • 5.弹框背景Drawable
    • 6.倒三角Drawable
    • 7.复制工具类
    • 8.调用
  • 总结


前言

根据时代进步,那些干产品的也叼砖起来了,今天就遇到一个需求,需要对TextView的文案进行自由选择复制,不怕,我们是勇敢牛牛。


一、效果图

在这里插入图片描述

二、实现步骤

1.OnSelectListener

public interface OnSelectListener {void onTextSelected(CharSequence content);
}

2.SelectionInfo类

代码如下(示例):

public class SelectionInfo {public int mStart;public int mEnd;public String mSelectionContent;
}

3.TextLayoutUtil类

package com.example.merchant.utils;import android.content.Context;
import android.text.Layout;
import android.widget.TextView;public class TextLayoutUtil {public static int getScreenWidth(Context context) {return context.getResources().getDisplayMetrics().widthPixels;}public static int getPreciseOffset(TextView textView, int x, int y) {Layout layout = textView.getLayout();if (layout != null) {int topVisibleLine = layout.getLineForVertical(y);int offset = layout.getOffsetForHorizontal(topVisibleLine, x);int offsetX = (int) layout.getPrimaryHorizontal(offset);if (offsetX > x) {return layout.getOffsetToLeftOf(offset);} else {return offset;}} else {return -1;}}public static int getHysteresisOffset(TextView textView, int x, int y, int previousOffset) {final Layout layout = textView.getLayout();if (layout == null) return -1;int line = layout.getLineForVertical(y);if (isEndOfLineOffset(layout, previousOffset)) {// we have to minus one from the offset so that the code below to find// the previous line can work correctly.int left = (int) layout.getPrimaryHorizontal(previousOffset - 1);int right = (int) layout.getLineRight(line);int threshold = (right - left) / 2; // half the width of the last characterif (x > right - threshold) {previousOffset -= 1;}}final int previousLine = layout.getLineForOffset(previousOffset);final int previousLineTop = layout.getLineTop(previousLine);final int previousLineBottom = layout.getLineBottom(previousLine);final int hysteresisThreshold = (previousLineBottom - previousLineTop) / 2;if (((line == previousLine + 1) && ((y - previousLineBottom) < hysteresisThreshold)) || ((line == previousLine - 1) && ((previousLineTop- y) < hysteresisThreshold))) {line = previousLine;}int offset = layout.getOffsetForHorizontal(line, x);if (offset < textView.getText().length() - 1) {if (isEndOfLineOffset(layout, offset + 1)) {int left = (int) layout.getPrimaryHorizontal(offset);int right = (int) layout.getLineRight(line);int threshold = (right - left) / 2; // half the width of the last characterif (x > right - threshold) {offset += 1;}}}return offset;}private static boolean isEndOfLineOffset(Layout layout, int offset) {return offset > 0 && layout.getLineForOffset(offset) == layout.getLineForOffset(offset - 1) + 1;}public static int dp2px(Context context, float dpValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5f);}
}

4.复制弹框的xml布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="match_parent"><LinearLayoutandroid:id="@+id/linearLayout"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/bg_operate_window"android:orientation="horizontal"android:paddingLeft="5dp"android:paddingRight="5dp"><TextViewandroid:id="@+id/tv_copy"style="@style/OperateTextView"android:text="@string/Copy" /><TextViewandroid:id="@+id/tv_select_all"style="@style/OperateTextView"android:text="@string/SelectAll" /></LinearLayout><ImageViewandroid:id="@+id/iv_triangle"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/linearLayout"android:layout_centerHorizontal="true"android:src="@drawable/triangle_down" />
</RelativeLayout>

5.弹框背景Drawable

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"><corners android:radius="5dp" /><solid android:color="#454545" /></shape>

6.倒三角Drawable

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"><item><rotateandroid:fromDegrees="45"android:pivotX="135%"android:pivotY="15%"><shape android:shape="rectangle"><sizeandroid:width="16dp"android:height="16dp" /><solid android:color="#454545" /></shape></rotate></item>
</layer-list>

7.复制工具类

package com.example.merchant.utils;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Build;
import android.text.Layout;
import android.text.Spannable;
import android.text.Spanned;
import android.text.style.BackgroundColorSpan;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.PopupWindow;
import android.widget.TextView;import androidx.annotation.ColorInt;import com.example.merchant.R;/*** 复制utils*/
public class SelectableTextHelper {private final static int DEFAULT_SELECTION_LENGTH = 1;private static final int DEFAULT_SHOW_DURATION = 100;private CursorHandle mStartHandle;private CursorHandle mEndHandle;private OperateWindow mOperateWindow;private SelectionInfo mSelectionInfo = new SelectionInfo();private OnSelectListener mSelectListener;private Context mContext;private TextView mTextView;private Spannable mSpannable;private int mTouchX;private int mTouchY;private int mSelectedColor;private int mCursorHandleColor;private int mCursorHandleSize;private BackgroundColorSpan mSpan;private boolean isHideWhenScroll;private boolean isHide = true;private ViewTreeObserver.OnPreDrawListener mOnPreDrawListener;ViewTreeObserver.OnScrollChangedListener mOnScrollChangedListener;public SelectableTextHelper(Builder builder) {mTextView = builder.mTextView;mContext = mTextView.getContext();mSelectedColor = builder.mSelectedColor;mCursorHandleColor = builder.mCursorHandleColor;mCursorHandleSize = TextLayoutUtil.dp2px(mContext, builder.mCursorHandleSizeInDp);init();}private void init() {mTextView.setText(mTextView.getText(), TextView.BufferType.SPANNABLE);mTextView.setOnLongClickListener(new View.OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {showSelectView(mTouchX, mTouchY);return true;}});mTextView.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {mTouchX = (int) event.getX();mTouchY = (int) event.getY();return false;}});mTextView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {resetSelectionInfo();hideSelectView();}});mTextView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {@Overridepublic void onViewAttachedToWindow(View v) {}@Overridepublic void onViewDetachedFromWindow(View v) {destroy();}});mOnPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {@Overridepublic boolean onPreDraw() {if (isHideWhenScroll) {isHideWhenScroll = false;postShowSelectView(DEFAULT_SHOW_DURATION);}return true;}};mTextView.getViewTreeObserver().addOnPreDrawListener(mOnPreDrawListener);mOnScrollChangedListener = new ViewTreeObserver.OnScrollChangedListener() {@Overridepublic void onScrollChanged() {if (!isHideWhenScroll && !isHide) {isHideWhenScroll = true;if (mOperateWindow != null) {mOperateWindow.dismiss();}if (mStartHandle != null) {mStartHandle.dismiss();}if (mEndHandle != null) {mEndHandle.dismiss();}}}};mTextView.getViewTreeObserver().addOnScrollChangedListener(mOnScrollChangedListener);mOperateWindow = new OperateWindow(mContext);}private void postShowSelectView(int duration) {mTextView.removeCallbacks(mShowSelectViewRunnable);if (duration <= 0) {mShowSelectViewRunnable.run();} else {mTextView.postDelayed(mShowSelectViewRunnable, duration);}}private final Runnable mShowSelectViewRunnable = new Runnable() {@Overridepublic void run() {if (isHide) return;if (mOperateWindow != null) {mOperateWindow.show();}if (mStartHandle != null) {showCursorHandle(mStartHandle);}if (mEndHandle != null) {showCursorHandle(mEndHandle);}}};private void hideSelectView() {isHide = true;if (mStartHandle != null) {mStartHandle.dismiss();}if (mEndHandle != null) {mEndHandle.dismiss();}if (mOperateWindow != null) {mOperateWindow.dismiss();}}private void resetSelectionInfo() {mSelectionInfo.mSelectionContent = null;if (mSpannable != null && mSpan != null) {mSpannable.removeSpan(mSpan);mSpan = null;}}private void showSelectView(int x, int y) {hideSelectView();resetSelectionInfo();isHide = false;if (mStartHandle == null) mStartHandle = new CursorHandle(true);if (mEndHandle == null) mEndHandle = new CursorHandle(false);int startOffset = TextLayoutUtil.getPreciseOffset(mTextView, x, y);int endOffset = startOffset + DEFAULT_SELECTION_LENGTH;if (mTextView.getText() instanceof Spannable) {mSpannable = (Spannable) mTextView.getText();}if (mSpannable == null || startOffset >= mTextView.getText().length()) {return;}selectText(startOffset, endOffset);showCursorHandle(mStartHandle);showCursorHandle(mEndHandle);mOperateWindow.show();}private void showCursorHandle(CursorHandle cursorHandle) {Layout layout = mTextView.getLayout();int offset = cursorHandle.isLeft ? mSelectionInfo.mStart : mSelectionInfo.mEnd;cursorHandle.show((int) layout.getPrimaryHorizontal(offset), layout.getLineBottom(layout.getLineForOffset(offset)));}private void selectText(int startPos, int endPos) {if (startPos != -1) {mSelectionInfo.mStart = startPos;}if (endPos != -1) {mSelectionInfo.mEnd = endPos;}if (mSelectionInfo.mStart > mSelectionInfo.mEnd) {int temp = mSelectionInfo.mStart;mSelectionInfo.mStart = mSelectionInfo.mEnd;mSelectionInfo.mEnd = temp;}if (mSpannable != null) {if (mSpan == null) {mSpan = new BackgroundColorSpan(mSelectedColor);}mSelectionInfo.mSelectionContent = mSpannable.subSequence(mSelectionInfo.mStart, mSelectionInfo.mEnd).toString();mSpannable.setSpan(mSpan, mSelectionInfo.mStart, mSelectionInfo.mEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);if (mSelectListener != null) {mSelectListener.onTextSelected(mSelectionInfo.mSelectionContent);}}}public void setSelectListener(OnSelectListener selectListener) {mSelectListener = selectListener;}public void destroy() {mTextView.getViewTreeObserver().removeOnScrollChangedListener(mOnScrollChangedListener);mTextView.getViewTreeObserver().removeOnPreDrawListener(mOnPreDrawListener);resetSelectionInfo();hideSelectView();mStartHandle = null;mEndHandle = null;mOperateWindow = null;}/*** Operate windows : copy, select all*/private class OperateWindow {private PopupWindow mWindow;private int[] mTempCoors = new int[2];private int mWidth;private int mHeight;public OperateWindow(final Context context) {View contentView = LayoutInflater.from(context).inflate(R.layout.layout_operate_windows2, null);contentView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));mWidth = contentView.getMeasuredWidth();mHeight = contentView.getMeasuredHeight();mWindow =new PopupWindow(contentView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, false);mWindow.setClippingEnabled(false);TextView tv_copy = contentView.findViewById(R.id.tv_copy);TextView tv_select_all = contentView.findViewById(R.id.tv_select_all);tv_copy.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//复制点击实现功能AppTk.Companion.showTimeDailog(mSelectionInfo.mSelectionContent, mContext);if (mSelectListener != null) {mSelectListener.onTextSelected(mSelectionInfo.mSelectionContent);}SelectableTextHelper.this.resetSelectionInfo();SelectableTextHelper.this.hideSelectView();}});tv_select_all.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {hideSelectView();selectText(0, mTextView.getText().length());isHide = false;showCursorHandle(mStartHandle);showCursorHandle(mEndHandle);mOperateWindow.show();}});}public void show() {mTextView.getLocationInWindow(mTempCoors);Layout layout = mTextView.getLayout();int posX = (int) layout.getPrimaryHorizontal(mSelectionInfo.mStart) + mTempCoors[0];int posY = layout.getLineTop(layout.getLineForOffset(mSelectionInfo.mStart)) + mTempCoors[1] - mHeight - 16;if (posX <= 0) posX = 16;if (posY < 0) posY = 16;if (posX + mWidth > TextLayoutUtil.getScreenWidth(mContext)) {posX = TextLayoutUtil.getScreenWidth(mContext) - mWidth - 16;}if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {mWindow.setElevation(8f);}mWindow.showAtLocation(mTextView, Gravity.NO_GRAVITY, posX, posY);}public void dismiss() {mWindow.dismiss();}public boolean isShowing() {return mWindow.isShowing();}}private class CursorHandle extends View {private PopupWindow mPopupWindow;private Paint mPaint;private int mCircleRadius = mCursorHandleSize / 2;private int mWidth = mCircleRadius * 2;private int mHeight = mCircleRadius * 2;private int mPadding = 25;private boolean isLeft;public CursorHandle(boolean isLeft) {super(mContext);this.isLeft = isLeft;mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setColor(mCursorHandleColor);mPopupWindow = new PopupWindow(this);mPopupWindow.setClippingEnabled(false);mPopupWindow.setWidth(mWidth + mPadding * 2);mPopupWindow.setHeight(mHeight + mPadding / 2);invalidate();}@Overrideprotected void onDraw(Canvas canvas) {canvas.drawCircle(mCircleRadius + mPadding, mCircleRadius, mCircleRadius, mPaint);if (isLeft) {canvas.drawRect(mCircleRadius + mPadding, 0, mCircleRadius * 2 + mPadding, mCircleRadius, mPaint);} else {canvas.drawRect(mPadding, 0, mCircleRadius + mPadding, mCircleRadius, mPaint);}}private int mAdjustX;private int mAdjustY;private int mBeforeDragStart;private int mBeforeDragEnd;@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mBeforeDragStart = mSelectionInfo.mStart;mBeforeDragEnd = mSelectionInfo.mEnd;mAdjustX = (int) event.getX();mAdjustY = (int) event.getY();break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:mOperateWindow.show();break;case MotionEvent.ACTION_MOVE:mOperateWindow.dismiss();int rawX = (int) event.getRawX();int rawY = (int) event.getRawY();update(rawX + mAdjustX - mWidth, rawY + mAdjustY - mHeight);break;}return true;}private void changeDirection() {isLeft = !isLeft;invalidate();}public void dismiss() {mPopupWindow.dismiss();}private int[] mTempCoors = new int[2];public void update(int x, int y) {mTextView.getLocationInWindow(mTempCoors);int oldOffset;if (isLeft) {oldOffset = mSelectionInfo.mStart;} else {oldOffset = mSelectionInfo.mEnd;}y -= mTempCoors[1];int offset = TextLayoutUtil.getHysteresisOffset(mTextView, x, y, oldOffset);if (offset != oldOffset) {resetSelectionInfo();if (isLeft) {if (offset > mBeforeDragEnd) {CursorHandle handle = getCursorHandle(false);changeDirection();handle.changeDirection();mBeforeDragStart = mBeforeDragEnd;selectText(mBeforeDragEnd, offset);handle.updateCursorHandle();} else {selectText(offset, -1);}updateCursorHandle();} else {if (offset < mBeforeDragStart) {CursorHandle handle = getCursorHandle(true);handle.changeDirection();changeDirection();mBeforeDragEnd = mBeforeDragStart;selectText(offset, mBeforeDragStart);handle.updateCursorHandle();} else {selectText(mBeforeDragStart, offset);}updateCursorHandle();}}}private void updateCursorHandle() {mTextView.getLocationInWindow(mTempCoors);Layout layout = mTextView.getLayout();if (isLeft) {mPopupWindow.update((int) layout.getPrimaryHorizontal(mSelectionInfo.mStart) - mWidth + getExtraX(),layout.getLineBottom(layout.getLineForOffset(mSelectionInfo.mStart)) + getExtraY(), -1, -1);} else {mPopupWindow.update((int) layout.getPrimaryHorizontal(mSelectionInfo.mEnd) + getExtraX(),layout.getLineBottom(layout.getLineForOffset(mSelectionInfo.mEnd)) + getExtraY(), -1, -1);}}public void show(int x, int y) {mTextView.getLocationInWindow(mTempCoors);int offset = isLeft ? mWidth : 0;mPopupWindow.showAtLocation(mTextView, Gravity.NO_GRAVITY, x - offset + getExtraX(), y + getExtraY());}public int getExtraX() {return mTempCoors[0] - mPadding + mTextView.getPaddingLeft();}public int getExtraY() {return mTempCoors[1] + mTextView.getPaddingTop();}}private CursorHandle getCursorHandle(boolean isLeft) {if (mStartHandle.isLeft == isLeft) {return mStartHandle;} else {return mEndHandle;}}public static class Builder {private TextView mTextView;private int mCursorHandleColor = 0xFF1379D6;private int mSelectedColor = 0xFFAFE1F4;private float mCursorHandleSizeInDp = 24;public Builder(TextView textView) {mTextView = textView;}public Builder setCursorHandleColor(@ColorInt int cursorHandleColor) {mCursorHandleColor = cursorHandleColor;return this;}public Builder setCursorHandleSizeInDp(float cursorHandleSizeInDp) {mCursorHandleSizeInDp = cursorHandleSizeInDp;return this;}public Builder setSelectedColor(@ColorInt int selectedBgColor) {mSelectedColor = selectedBgColor;return this;}public SelectableTextHelper build() {return new SelectableTextHelper(this);}}
}

8.调用

private var mSelectableTextHelper: SelectableTextHelper? = null//实例化
//text为文案
mSelectableTextHelper = SelectableTextHelper.Builder(text).setSelectedColor(Color.parseColor("#afe1f4")).setCursorHandleSizeInDp(20f).setCursorHandleColor(Color.parseColor("#0d7aff")).build()

总结

感觉东西是有点多,但比较实用,而且直接复制去就可以用,自己写主要费大脑不是。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/157060.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Xcode升级到15.0 解决DT_TOOLCHAIN_DIR问题

根据个人开发遇到的问题做的总结&#xff0c;公司要求Xcode 14.2 &#xff0c;Swift 5.7开发&#xff0c;由于升级了Mac 14.0系统后&#xff0c;Xcode 14.2不能使用&#xff0c;解决方案目前有2个 一、在原来Xcode 14.2 的显示包内容&#xff0c;如图 二、升级到Xcode的15.0后…

yolov8 (2) : 模型训练

yolov8 github: https://github.com/ultralytics/ultralytics yolov8 网络详解参见: YOLOv8 (1) : 网络讲解1. 环境安装 安装ultralytics包pip install ultralytics在终端输入yolo命令࿰

软件TFN 2K的分布式拒绝攻击(DDos)实战详解

写在前头 本人写这篇博客的目的&#xff0c;并不是我想成为黑客或者鼓励大家做损坏任何人安全和利益的事情。因科研需要&#xff0c;我学习软件TFN 2K的分布式拒绝攻击&#xff0c;只是分享自己的学习过程和经历&#xff0c;有助于大家更好的关注到网络安全及网络维护上。 需要…

饥荒服务器阿里云租用价格表一年和一个月收费报价表

饥荒阿里云服务器多少钱一个月&#xff1f;阿里云服务器价格9元一个月&#xff0c;阿里云轻量应用服务器2核2G3M带宽轻量服务器一年108元&#xff0c;2核4G4M带宽轻量服务器一年297.98元12个月&#xff1b;阿里云ECS云服务器e系列2核2G配置182元一年、2核4G配置365元一年、2核8…

信必优收到全国性综合类证券客户表扬信

近日&#xff0c;信必优收到全国性综合类证券客户表扬信&#xff0c;客户高度表扬我司驻场员工认真负责的态度和专业扎实的技术能力&#xff0c;任务承担快&#xff0c;工作效率高&#xff0c;对项目顺利开展做出了积极贡献。 客户成立于1988年&#xff0c;在全国21个省级区域…

京东数据平台:2023年9月京东洗衣机行业品牌销售排行榜

鲸参谋监测的京东平台9月份洗衣机市场销售数据已出炉&#xff01; 9月份洗衣机行业销售呈下滑状态。鲸参谋数据显示&#xff0c;9月京东平台洗衣机的总销量为116万&#xff0c;环比下滑约1%&#xff0c;同比下滑约13%&#xff1b;月销售额为17亿&#xff0c;环比下滑约7%&…

【mysql】 bash: mysql: command not found

在linux 服务器上安装了mysql 也可以正常运行。 但是执行命令&#xff0c;系统提示&#xff1a;bash: mysql: command not found bash:mysql:找不到命令 执行的命令是&#xff1a; mysql -u root -h 127.0.0.1 -p由于系统默认会查找的 /usr/bin/ 中下的命令&#xff0c;如…

JVM监控及诊断工具-GUI篇

文章目录 JVM监控及诊断工具-GUI篇工具概述JConsoleVisual VM再谈内存泄漏Java中内存泄漏的8种情况Arthas&#xff08;阿尔萨斯&#xff09;康师傅使用阿尔萨斯的例子help指令 JVM监控及诊断工具-GUI篇 工具概述 使用上一章命令行工具或组合能获取目标Java应用性能相关的基础…

Java架构师缓存架构设计

目录 1 导学2 高性能概述2.1 高性能的定义和衡量指标2.2 如何实现高性能的计算机系统或软件程序2.3 木桶理论2.4 如何实现计算机系统或软件程序的高性能3 多级缓存设计3.1 浏览器缓存3.2 CDN缓存3.3 负载均衡的缓存3.4 进程内缓存3.5 分布式缓存4 缓存技术方案5 如何进行缓存拆…

智能防眩目前照灯系统控制器ADB

经纬恒润的自适应远光系统—— ADB&#xff08;Adaptive Driving Beam&#xff09; 是一种能够根据路况自适应变换远光光型的智能远光控制系统。根据本车行驶状态、环境状态以及道路车辆状态&#xff0c;ADB 系统自动为驾驶员开启或退出远光。同时&#xff0c;根据车辆前方视野…

剧院建筑三维可视化综合管控平台提高安全管理效率

随着数字孪生技术的高速发展&#xff0c;智慧楼宇也被提上日程&#xff0c;以往楼宇管理存在着设备故障排查困难、能源浪费与管理不足、安全性和风险高等问题&#xff0c;而智慧楼宇数字孪生可视化中控平台&#xff0c;打造智慧楼宇管理一张图&#xff0c;实现了智慧建筑和楼宇…

美创科技三重数据安全韧性,杜绝删库跑路

从删库到跑路&#xff0c;教训很多&#xff0c;但类似事件近年来总在重复上演&#xff0c;有运维部为此连夜鏖战恢复&#xff0c;更有企业陷入“至暗时刻”&#xff0c;经济受损、名誉蒙尘。 组织单位应该采取怎样的策略和积极主动的方法&#xff0c;避免酿成严重的后果&#x…

为什么B2B企业需要CRM系统?如何利用它最大化销售额?

身处 B2B 企业&#xff0c;你是否正在为冗长复杂的销售流程而苦恼&#xff1f;你是否经常感到无法控制来之不易的销售线索&#xff0c;所有的营销努力都付诸东流&#xff1f; 实际上&#xff0c;这些问题正是大多数 B2B 企业面临的共同挑战。但是&#xff0c;为你的B2B业务采用…

16.(开发工具篇mysql)mysql不同库同步数据的异常记录

1:mysql导入时出现“ERROR at line : Unknown command ‘\‘‘.“的解决办法 default-character-set=utf82:ERROR 2006 (HY000) at line 71: MySQL server has gone away (1) 连接超时 查看各项连接时间: show global variables like %timeout;这些值是相对是MySQL的默认…

视频太大怎么压缩变小?超过1G的视频这样压缩

视频已经成为了我们日常生活中不可或缺的一部分&#xff0c;然而&#xff0c;很多时候&#xff0c;我们可能会遇到视频文件过大&#xff0c;无法在某些平台上传或保存的问题。那么&#xff0c;如何将过大的视频文件压缩变小呢&#xff1f; 下面就给大家分享三款实用的工具&…

Nacos 小bug: application.properties配置未生效,导致端口未生效

最近用了下nacos 1.4.6 ,发现windows 中修改配置中的启动端口未生效&#xff0c;其实就是配置文件没读取到。 去github 逛了一下issue ,参考这个&#xff1a;https://github.com/alibaba/nacos/issues/10217 这哥们儿是nacos 1.4.5 Linux系统下的相同问题&#xff0c;shell 中…

SpringCloud溯源——从单体架构到微服务Microservices架构 分布式和微服务 为啥要用微服务

前言 单体架构好好的&#xff0c;为啥要用微服务呢&#xff1f;微服务究竟是啥&#xff0c;怎么来的&#xff0c;有啥优缺点&#xff0c;本篇博客尝试追根溯源&#xff0c;阐述单体应用到分布式&#xff0c;微服务的演变,微服务架构的定义及优缺点&#xff0c;厘清相关的概念。…

dubbo3+zookeeper/nacos+dubbo-admin

工程结构&#xff1a; 版本信息&#xff1a; jdk版本&#xff1a;1.8 springboot-parent版本&#xff1a;2.6.6springboot版本&#xff1a;2.6.6 dubbo-spring-boot-starter版本&#xff1a;3.0.7dubbo版本&#xff1a;3.0.7 dubbo-registry-zookeeper版本&#xff1a;3.0.7c…

高级网络调试技巧:使用Charles Proxy捕获和修改HTTP/HTTPS请求

今天我将与大家分享一种强大的网络调试技巧&#xff0c;那就是使用Charles Proxy来捕获和修改HTTP/HTTPS请求。如果您是一位开发人员或者网络调试爱好者&#xff0c;那么这个工具肯定对您有着很大的帮助。接下来&#xff0c;让我们一起来学习如何使用Charles Proxy进行高级网络…