热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

taro请务必在小程序页面中完善页面基础信息_如何快速独立开发完复杂的小程序?...

随着业务需求的不断累加、小程序追求快速产出。在人手不足且开发周期较短的情况下,我们需要找到一个最大化开发效率的方法。而高效率的开发离不开规范化、工程化、组件化。为此整

随着业务需求的不断累加、小程序追求快速产出。

在人手不足且开发周期较短的情况下,我们需要找到一个最大化开发效率的方法。

而高效率的开发离不开规范化、工程化、组件化。

为此整理写下总结,细数小程序中的坑与实践。

介绍我们对小程序高效率开发的思考与探索。

  • 布局方案

    • 导航栏

    • TabBar

    • BasicPage

  • 用户系统

    • 登录方案

    • 初始化登录

    • 鉴权

  • 优化及 Bug 追踪

    • 日志收集

    • 数据分析

  • 常用优化方案

    • preLoad

    • 独立分包加载

布局方案

我们首先思考的是,在小程序中如何快速且高还原产出页面。

为此我们封装了一套页面组件。

导航栏

目前小程序有如下两种导航栏:常规、自定义导航栏

c0f127598c57a2f1332233bc9a5a4391.png

常规

8878a2ed01c8601fd9827c147eda4abc.png

自定义导航栏

be55d6eba88d2a4f823e63ae396fb237.png

自定义导航栏

常规布局下,顶部导航栏部分直接使用小程序提供导航栏。

自定义导航栏布局下,我们可以完全控制导航栏样式,赋予导航栏更多交互及 UI 设计上的可能。如上图所示,Readhub 在导航栏中加入了设置按钮,喜茶在个人页中标题渐隐及沉浸式导航栏效果。

可根据具体业务选择具体布局方案,在我们小程序中,我们选择了全部使用自定义导航栏的方式并对其进行了一定封装。

在确定使用自定义导航栏方案后,我们对导航栏进行了拆解

8fd67fc617f3a830ab25339d2eeb3f8f.png

拆解后,我们发现可以将自定义导航栏分为两个部分:StatusBar 及 NavigationBar 。

通过查阅微信 API ,我们分别通过 wx.getSystemInfoSync 及 wx.getMenuButtonBoundingClientRect 获取到 StatusBarHeight 及 MenuButton 的布局信息。

由拆解图可知

1NavigationBarPaddingTop = MenuButtonTop - StatusBarHeight
2
3NavigationBarPaddingBottom = NavigationBarPaddingTop
4
5NavigationBar = StatusBarHeight + NavigationBarPaddingTop + NavigationBarPaddingBottom + MenuButtonHeight

得到上述数据后,结果简单封装, 我们得到如下方案

e9ef55c594f16292667ad5ad919480e7.png

StatusBar 部分, 我们使用 PaddingTop 填充。

可在此基础上可再进一步封装一些通用 NavigationBar 组件。

我们封装了一些常用 NavigationBar 组件, 如下所示:

2717af2fe9a5bad2ec96d22d2be4a955.png
78152b1eef53a4b64ecfad9c6196f6f4.png
91d93a66b958d57fc9e749651bcae3ca.png
23f2b6bdc9bd5afd52b1e805ab2ebead.png
沉浸式导航栏

自定义 TabBar

目前小程序 TabBar 中也存在两种方案。

常规 TabBar :微信提供方案,可修改 icon 、 文字及其对应选中状态。

自定义 TabBar :小程序基础库 2.5.0 开始支持。可通过其实现异形 TabBar 或各种自定义样式。

e27d36975d40cc19ba54c32dda6c3b6e.png

普通TabBar

f404e2f6131da26e7a740461f2ca9a08.png异形TabBar

6662d6473c29e90a86acdfa655c736e6.png仅图标TabBar


在我们小程序中,我们选择全部使用自定义 TabBar 来实现业务。

由于小程序基础库 2.5.0 之后官方才开始支持自定义 TabBar 。我们此处不直接选择使用 custom-tab-bar 方案。选择结合 custom-tab-bar 、 自定义组件及 wx.hideTabBar 的方案实现。

具体方案为放置空节点 custom-tab-bar 文件。在页面中按需引入自定义 TabBar 组件。在页面初始化完成后调用 wx.hideTabBar 隐藏原 TabBar 。

这样做的好处在于,在基础库 2.5.0 及更高版本时正常显示,在低版本时以最小代价兼容。

edc23d9e5877d9319768ce19157739ed.png普通f404e2f6131da26e7a740461f2ca9a08.png异形TabBar


在 iPhone X 系列下的底部安全区兼容方案如下

1@mixin media-style() {
2  .tab {
3    padding-bottom: 84px;
4  }
5}
6// 适配iPhone X系列下巴
7@media screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) {
8    @include media-style();
9}
10
11@media only screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio:3) {
12    @include media-style();
13}
14
15@media only screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio:2) {
16    @include media-style();
17}
18// 下面代码只为适配iPhone X在微信调试模拟器中为724px
19@media screen and (device-width: 375px) and (device-height: 724px) and (-webkit-device-pixel-ratio: 3) {
20    @include media-style();
21}

推荐如无特殊需求,建议直接使用微信提供方案,在自定义 TabBar 方案中 安卓手机下拉刷新时, TabBar 会被拉出可视区域。需自定义下拉刷新组件解决

方案整合 BasicPage

以上方案在线上运行一段时间后稳定后。对自定义导航栏及自定义 TabBar 方案进行了整合。封装了 BasicPage 组件。

以我们线上典型页面为例,我们可以将页面分为两大类。

3e2fe00bc0cc173668c1c83e71d82b55.png三段式结构5570ac25cd556bf409a56f65d213fab8.png无 TabBar


基于以上分析结合线上需求,我们对此基础组件进行封装。

Taro 框架伪代码,可根据各自使用框架进行封装,思路一致

1class BasicPage extends Taro.Component {
2
3  state = {
4    menuButtonHeight: 32,
5    menuButtonTop: 48,
6    statusBarHeight: 44,
7  };
8
9  componentDidMount() {
10        // ...获取并设置 menuButtonHeight 、 menuButtonTop 、 statusBarHeight
11  }
12
13  render() {
14    return (
15      16        {17          this.props.header && 22            {this.props.renderHeader}23          View>24        }25        26          {this.props.renderBody}27        View>28        {this.props.tab && }29      View>30    );31  }32}3334BasicPage.defaultProps = {35  fixed: false, // header 是否浮动36  tab: false,37  header: false,38  tabActive: 'template',39};40

使用中会经常用到 自定义 TabBar 、 自定义 NavigationBar 布局数据。再封装一个工具类获取。

1import Taro from "@tarojs/taro";
2
3function rpx2px(rpx, windowWidth) {
4  return rpx / 750 * windowWidth;
5}
6
7export default class customConfig {
8
9  static fetchAllConfig() {
10    const menuButton = Taro.getMenuButtonBoundingClientRect();
11    const systemInfo = Taro.getSystemInfoSync();
12
13    const statusBarHeight = systemInfo.statusBarHeight;
14    const headerHeight = (menuButton.top - systemInfo.statusBarHeight) * 2 + menuButton.height;
15    const footerHeight = systemInfo.model.indexOf('iPhone X') === -1
16      ?
17      rpx2px(100, systemInfo.windowWidth)
18      :
19      rpx2px(168, systemInfo.windowWidth);  // 50  84
20    const bodyHeight = systemInfo.windowHeight - statusBarHeight - headerHeight - footerHeight;
21    const noTabBodyHeight = systemInfo.windowHeight - statusBarHeight - headerHeight;
22
23    let data = {
24      source: {
25        menu: menuButton,
26        system: systemInfo,
27      },
28      height: {
29        statusBar: statusBarHeight,
30        header: headerHeight,
31        body: bodyHeight,
32        noTabBody: noTabBodyHeight,
33        footer: footerHeight,
34      },
35    };
36    Taro.setStorageSync('customConfig', data);
37    return data;
38  }
39
40  static get config() {
41    let storageInfoSync = Taro.getStorageSync('customConfig');
42    if(!storageInfoSync) {
43      storageInfoSync = this.fetchAllConfig();
44    }
45    return storageInfoSync;
46  }
47}

到此,我们完成对基础页面组件的封装。目前线上运行小程序所有页面都基于该组件进行开发。

开发新页面时只需要引用该组件即可。

1'index' 2        renderHeader={ 3           4            className='my-index-header' 5          > 6            TitleText> 7           8        } 9        renderBody={10          11            Body12          View>13        }14/>用户系统

在一个应用中,用户系统是至关重要的。我们通过数个小程序的开发,整理了一套我们目前正在使用的用户系统实践。

登录、获取用户信息

371e00bd71afc4cbf7e0762ae8538225.png登录流程c9e535b0adc52316d150a8dd3de859e8.png获取用户信息

如上图所示,我们将小程序登录及获取用户信息拆分为两部分。

主要有如下考虑:

  1. 降低用户使用门槛,可先让用户体验部分功能。后续分享或互动时提示授权完善用户信息

  2. 保证始终持有用户登录态,方便程序处理。如把用户登录及完善用户信息放置一起,在未授权时无法获取自定义登录态。判断变得复杂且无法提前收集 formId

  3. 同一开发者账号下,多小程序互通时,如有一小程序用户授权过,可通过返回 unionid 直接同步信息,无需再授权,提升用户体验。

处理注意点

授权获取用户信息时,如果服务端未记录用户 sessionKey ,在 Button type = getUserInfo 回调事件中使用 wx.login 方法获取 code 的话,会导致 sessionKey 变化。从而导致 getUserInfo 时使用 sessionKey 与新 sessionKey 不匹配。从而导致解密用户信息失败。

解决方案有如下两种:

  • Button type = getUserInfo 回调事件中使用 wx.login 方法后,再次调用 wx.getUserInfo 方法重新获取加密用户信息。

  • 服务端记录 sessionKey ,Button type = getUserInfo 回调后无需调用 wx.login ,直接提交供服务端处理。

第一种方案适合简单改造旧项目、快速开发,但强烈建议使用服务端处理方式解决。

完善用户信息时,解密用户信息部分请查看官方文档,这里不叙述具体流程https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html

unionid 机制

另外,在登录流程中服务端向微信换取 sessionKey 过程中,如果满足一定条件,会直接返回 unionid 。同开发者账号下多个小程序时可用 unionid 做用户信息同步,无需再授权。提升用户体验。

unionid 机制: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/union-id.html

小程序初始化及页面初始化处理

在日常开发中,我们通常会把登录获取 token 操作放置在小程序初始化中即 app.js 定义的 onLaunch 中。而该生命周期与页面初始化生命周期为同步进行。

此时,如果在页面初始化中,需要携带用户登录态请求接口获取信息时,可能出现如下情况

268c56a59f721b11fba0a8aed7ec591d.png

因为小程序初始化及页面初始化是同步进行的。若页面初始化时,小程序初始化中登录请求仍未完成。会导致未携带 token 或其他鉴权信息,鉴权失败。

最开始我们通过在组件中挂载一个特殊事件 componentDidInit ,待小程序初始化登录请求后获取当前页面实例进行调用。但该方案对代码侵入性太强,最终我们选择维护一个登录请求队列。

f92a21d061d8e8dc24ea8e31ab578d6f.png

用上队列的原因在于,在产品需求上经常会有先跳入首页,再从首页跳入二级页的需求,这样能让用户回退一次后,仍然能回到首页。但会导致在不同页面中近乎同时调用 login 方法。

在第一种方案中,解决该问题需要获得所有页面实例进行调用。而引入队列后只需要轮询消费队列中函数执行即可。上述流程可解决此问题。伪代码如下:

代码仅供理解思路

1let loginDoing = false;
2const loginEvent = [];
3
4const userProfile = observable({
5  user: {
6    avatar: '',
7    isCompleted: false,
8    nickname: '',
9    uid: 0,
10    token: '',
11  },
12  async loginProcess() {
13    if(this.user.token) {
14      return this.user;
15    }
16    loginDoing = true;
17    let code;
18    try {
19      const codeResult = await Taro.login();
20      if(codeResult.errMsg !== 'login:ok') {
21        throw new Error('Taro.login 失败');
22      }
23      code = codeResult.code;
24    } catch (e) {
25      loginDoing = false;
26      throw e;
27    }
28    const result = await post(URL().user.login, {
29      code,
30    });
31    let user = {
32      ...result.user,
33      token: result.token,
34    };
35    this.user = user;
36    loginDoing = false;
37    setTimeout(() => {
38      let length = loginEvent.length;
39      for(let i = 0; i 40        loginEvent.pop()(user);
41      }
42    });
43    return user;
44  },
45  login() {
46    if(loginDoing) {
47      return new Promise((resolve) => {
48        loginEvent.push(resolve);
49      });
50    } else {
51      return this.loginProcess()
52    }
53  },
54});

鉴权

业务需求中,通常存在某些操作需要 【 用户授权完善信息 】 后才能继续进行,早期项目中都是各自页面中写鉴权代码。因而会涉及大量重复代码,也不利于快速开发。为此我们封装了一套鉴权方案。

BasePage

通过所有页面基础一个基类 BasePage 。在 BasePage 中写入鉴权逻辑来实现。配合在主页面中使用 AuthorizationModal 组件实现鉴权。

代码仅供理解思路

1export default class BasePage extends Component {
2
3    state = {
4        // 鉴权相关
5        showAuthorizationModal: false,
6    };
7
8    /** 9     * 鉴权相关10     */
11    // 授权成功事件
12    authSuccessEvent() {
13    }
14
15    // 取消授权事件
16    authFailEvent() {
17    }
18
19    async checkAuthorization() {
20        // 当前是否有已验证
21        let globalData = getGlobalData(STORAGE_KEY.VERIFY);
22        if(globalData) {
23            return {
24                isNew: false,
25            };
26        } else {
27            Taro.showLoading({
28                title: '检查授权中...',
29                mask: true,
30                showTicketModal: false,
31            });
32            // 如果本地不存在时,先请求接口
33            // 未登录过,或新机器
34            // 请求token及授权状态
35            let res;
36            try {
37                res = await Taro.login();
38            } catch() {
39                Toast.fail('登录失败~');
40                Taro.hideLoading();
41                throw new Error('Taro.login 失败');
42            }
43            // 请求授权接口
44            const result = {};
45            if(result.errno === 0) {
46                resolve({
47                    isNew: false,
48                });
49            } else {
50                // 未授权过
51                // 弹窗提示授权
52                this.setState({
53                    showAuthorizationModal: true,
54                });
55                this.authSuccessEvent = () => {
56                    this.setState({
57                        showAuthorizationModal: false,
58                    });
59                    resolve({
60                        isNew: true,
61                    });
62                };
63                this.authFailEvent = () => {
64                    this.setState({
65                        showAuthorizationModal: false,
66                    });
67                    reject();
68                };
69            }
70        }
71    }
72}

页面继承该基类

1class LaunchIndex extends BasePage {}

在页面中置入组件

1{this.state.showAuthorizationModal &&
2}3

19db6b829372abfa3a3d12c72ce2db3f.pngAuthorizationModal 组件

接下来,我们只需要在需要鉴权的操作中如下使用即可

1this.checkAuthorization()
2  .then((res) => {
3   // 授权成功逻辑
4       console.log('是否新用户', res.isNew);
5   })
6   .catch(() => {
7    // 授权失败逻辑
8    })

该方案好处在于,授权由状态驱动,只需在代码中调用 checkAuthorization 方法即可。

AuthorizationView

后来,由于第一种方案过于重,对页面代码侵入性较强。为此我们又封装了一套较轻的组件。

大部分逻辑中,需要用户主动点击时才进行鉴权,我们基于此思路封装了 AuthorizationView 。对外暴露 onAgree 、 onDeny 方法实现对部分区域的点击鉴权操作。

代码仅供理解思路

1class AuthorizationView extends Taro.Component {
2
3  state = {
4    showLoginPanel: false,
5  };
6
7  /** 8   * 登录 9   */
10  click() {
11    const { userProfile: { user, }, } = this.props;
12    if(user.isCompleted) {
13      this.props.onAgree(user);
14    } else {
15      // 显示登录框
16      this.setState({
17        showLoginPanel: true,
18      });
19    }
20  }
21
22  /**23   * 授权登录24   * @param e25   */
26  async bindGetUserInfo(e) {
27    if(e.detail.errMsg === 'getUserInfo:ok') {
28      const { userProfile, } = this.props;
29      const userResult = await userProfile.login(true);
30      this.setState({
31        showLoginPanel: false,
32      });
33      this.props.onAgree(userResult);
34    } else {
35      this.props.onDeny();
36    }
37  }
38
39  cancel() {
40    this.setState({
41      showLoginPanel: false,
42    });
43  }
44
45  render() {
46    return (
47      48        {this.props.children}View>49        {50          this.state.showLoginPanel && 51            52              您还未登录View>53              请先登录再进行操作View>54              55              56                暂不登录View>57                58                  立即登录View>59                Button>60              View>61            View>62          View>63        }64      Block>65    );66  }67}6869AuthorizationView.defaultProps = {70  onAgree: () => {71  },72  onDeny: () => {73  },74};7576export default AuthorizationView;77

代码中只需要使用该组件包裹子组件即可使用

1this.onAgree.bind(this)} onDeny={this.onDeny.bind(this)}>2  生成海报View>34

以上两种方案都有在线上业务中使用,具体选型看业务决定

优化及Bug追踪

在维护阶段,我们会更加关注于用户反馈 bug 时如何复现场景及数据分析。

日志收集

在小程序基础库版本 2.1.0 后,微信提供了一套日志相关接口:LogManager 。

在用户反馈时,通过该接口记录的日志会同步上传至微信后台,可下载查看追踪 Bug。

我们通过简单的对其封装,实现一套日志收集机制。

1const _logger = Taro.getLogManager({ level: 0, });
2
3const Logger = {
4  debug(...args) {
5    _logger.debug(`${dayjs().format('YYYY-MM-DD HH:mm:ss')} ?`, ...args);
6    console.debug(`${dayjs().format('YYYY-MM-DD HH:mm:ss')} ?`, ...args);
7  },
8  info(...args) {
9    _logger.info(`${dayjs().format('YYYY-MM-DD HH:mm:ss')} ?`, ...args);
10    console.info(`${dayjs().format('YYYY-MM-DD HH:mm:ss')} ?`, ...args);
11  },
12  warn(...args) {
13    _logger.warn(`${dayjs().format('YYYY-MM-DD HH:mm:ss')} ⚠️`, ...args);
14    console.warn(`${dayjs().format('YYYY-MM-DD HH:mm:ss')} ⚠️`, ...args);
15  },
16  error(...args) {
17    _logger.warn(`${dayjs().format('YYYY-MM-DD HH:mm:ss')} [ Error ] ❌️`, ...args);
18    console.error(`${dayjs().format('YYYY-MM-DD HH:mm:ss')} [ Error ] ❌️`, ...args);
19  },
20};
21
22export default Logger;

在使用时,最好按照一定规范进行使用,方便后续查找。例如

1Logger.error('[ MyIndex ] 获取用户信息失败', e);
2Logger.debug('[ LaunchIndex ] init response', info);

实时日志分析:小程序基础库 2.7.1 之后还提供了 实时日志分析功能。https://developers.weixin.qq.com/miniprogram/dev/api/base/debug/wx.getRealtimeLogManager.html

数据分析

5901d53a2200cec6e12c4cc47aab626f.png
数据分析模型

在产品迭代过程中,我们一般会依照上面模型进行迭代。

数据获取 → 数据分析 → 数据应用 → 数据反馈

在小程序中,数据获取的方案主要有

  • 小程序后台自定义分析

    小程序本身提供的数据平台。

    优点在于能随时不发版本添加数据打点位置。能满足大部分需求。

    主要依靠产品后台自行添加数据打点项目。

  • 第三方数据平台

    这里以阿拉丁自定义数据分析为例。依靠第三方平台提供 API 进行打点。

    • 阿拉丁

    • ……

  • 自有数据分析平台

    一般大厂都会有自己自有数据分析平台,联系数据组拓展即可

推荐使用小程序后台自定义分析进行打点。各数据平台打点大同小异,能不发版本添加数据打点才是大杀器。

阿拉丁数据平台打点封装,代码仅供理解思路

1import Taro from '@tarojs/taro';
2
3export default class Monitor {
4  static sendEvent(moduleName, eventName, options) {
5    let aldstat = Taro.getApp().aldstat;
6    if(aldstat) {
7      aldstat.sendEvent(`[ ${moduleName} ] ${eventName}`, options);
8    }
9  }
10}
11
12Monitor.sendEvent('LaunchIndex', '返回', {
13  id: this.state.id,
14});
15
16Monitor.sendEvent('LaunchIndex', '点击制作', {
17  id: this.state.id,
18});

小程序自定义分析API方式依葫芦画瓢封装即可。

需要注意的是封装时要有逻辑、有规则的封装,方便后面筛选具体页面具体操作。

常用优化方案

preLoad

在微信小程序中,页面路由跳转时 ( 例如调用 wx.navigateTo 、wx.redirectTo 或 wx.switchTab ) ,到页面触发 componentWillMount 会有一定延时。因此一些网络请求可以提前到跳转前一刻请求。而后在触发 componentWillMount 后取得该请求实例。

目前各框架均提供了预加载请求实现。原生开发可自行拓展,思路一致。以下以 Taro 为例。代码仅供理解思路。

1export default class Preload extends BasePage {
2    componentWillMount() {
3        let initData;
4        // 兼容直接进入的场景
5        if(this.$preloadData) {
6            initData = this.$preloadData;
7        } else {
8            initData = request(URL().user.defaultAddress, {
9                token: getGlobalData(STORAGE_KEY.ACCESS_TOKEN),
10            });
11        }
12        initData
13            .then((initInfo) => {
14            })
15            .catch(() => {
16            });
17    }
18
19    componentWillPreload (params) {
20        return request(URL().user.defaultAddress, {
21            token: getGlobalData(STORAGE_KEY.ACCESS_TOKEN),
22        });
23    }
24}

独立分包加载

https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages.html

除上面列出尝试外。我们还做了以下工作:

  • 通用分享图解决方案

  • 小程序云开发应用

  • 自定义下拉刷新组件 RefreshView

  • Protobuf

  • 图片裁剪组件

还有一些你可能遇不到的坑

  • 原生组件使用问题

  • Video 、 innerAudioContext

由于不是必要部分,篇幅有限,不在此一一列举

价值

在对小程序进行上述实践后,我们已经能够基于该实践快速开发复制小程序。我们最近一个小程序 【嘟嘟卡点相册】 仅开发5天后就上线了。

纸上得来终觉浅,绝知此事要躬行。

文章内容基本囊括了开发维护阶段可能会用到的点及我们对此作出的应对方案。供参考。

本文仅为抛砖引玉, 软件开发没有银弹,好的方案一定是与业务息息相关的。欢迎交流。

推荐小程序系列文章:

强烈推荐星标31k的小程序资源项目,资源很全!

推荐项目| 微信小程序富文本解析组件-wxParse

微信小程序开发实践入门教程

9fb2e93b12a19675382de2f0c2e28e99.png




推荐阅读
  • 数字图书馆近期展出了一批精选的Linux经典著作,这些书籍虽然部分较为陈旧,但依然具有重要的参考价值。如需转载相关内容,请务必注明来源:小文论坛(http://www.xiaowenbbs.com)。 ... [详细]
  • 本文介绍了如何利用Shell脚本高效地部署MHA(MySQL High Availability)高可用集群。通过详细的脚本编写和配置示例,展示了自动化部署过程中的关键步骤和注意事项。该方法不仅简化了集群的部署流程,还提高了系统的稳定性和可用性。 ... [详细]
  • 在ElasticStack日志监控系统中,Logstash编码插件自5.0版本起进行了重大改进。插件被独立拆分为gem包,每个插件可以单独进行更新和维护,无需依赖Logstash的整体升级。这不仅提高了系统的灵活性和可维护性,还简化了插件的管理和部署过程。本文将详细介绍这些编码插件的功能、配置方法,并通过实际生产环境中的应用案例,展示其在日志处理和监控中的高效性和可靠性。 ... [详细]
  • 在本文中,我们将详细介绍如何构建一个用于自动回复消息的XML类。当微信服务器接收到用户消息时,该类将生成相应的自动回复消息。以下是具体的代码实现:```phpclass We_Xml { // 代码内容}```通过这个类,开发者可以轻松地处理各种消息类型,并实现高效的自动回复功能。我们将深入探讨类的各个方法和属性,帮助读者更好地理解和应用这一技术。 ... [详细]
  • Amoeba 通过优化 MySQL 的读写分离功能显著提升了数据库性能。作为一款基于 MySQL 协议的代理工具,Amoeba 能够高效地处理应用程序的请求,并根据预设的规则将 SQL 请求智能地分配到不同的数据库实例,从而实现负载均衡和高可用性。该方案不仅提高了系统的并发处理能力,还有效减少了主数据库的负担,确保了数据的一致性和可靠性。 ... [详细]
  • 在多年使用Java 8进行新应用开发和现有应用迁移的过程中,我总结了一些非常实用的技术技巧。虽然我不赞同“最佳实践”这一术语,因为它可能暗示了通用的解决方案,但这些技巧在实际项目中确实能够显著提升开发效率和代码质量。本文将深入解析并探讨这四大高级技巧的具体应用,帮助开发者更好地利用Java 8的强大功能。 ... [详细]
  • 本文深入探讨了Java多线程环境下的同步机制及其应用,重点介绍了`synchronized`关键字的使用方法和原理。`synchronized`关键字主要用于确保多个线程在访问共享资源时的互斥性和原子性。通过具体示例,如在一个类中使用`synchronized`修饰方法,展示了如何实现线程安全的代码块。此外,文章还讨论了`ReentrantLock`等其他同步工具的优缺点,并提供了实际应用场景中的最佳实践。 ... [详细]
  • 在本地环境中部署了两个不同版本的 Flink 集群,分别为 1.9.1 和 1.9.2。近期在尝试启动 1.9.1 版本的 Flink 任务时,遇到了 TaskExecutor 启动失败的问题。尽管 TaskManager 日志显示正常,但任务仍无法成功启动。经过详细分析,发现该问题是由 Kafka 版本不兼容引起的。通过调整 Kafka 客户端配置并升级相关依赖,最终成功解决了这一故障。 ... [详细]
  • 提升 Kubernetes 集群管理效率的七大专业工具
    Kubernetes 在云原生环境中的应用日益广泛,然而集群管理的复杂性也随之增加。为了提高管理效率,本文推荐了七款专业工具,这些工具不仅能够简化日常操作,还能提升系统的稳定性和安全性。从自动化部署到监控和故障排查,这些工具覆盖了集群管理的各个方面,帮助管理员更好地应对挑战。 ... [详细]
  • 技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告
    技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告 ... [详细]
  • 微信小程序实现类似微博的无限回复功能,内置云开发数据库支持
    本文详细介绍了如何利用微信小程序实现类似于微博的无限回复功能,并充分利用了微信云开发的数据库支持。文中不仅提供了关键代码片段,还包含了完整的页面代码,方便开发者按需使用。此外,HTML页面中包含了一些示例图片,开发者可以根据个人喜好进行替换。文章还将展示详细的数据库结构设计,帮助读者更好地理解和实现这一功能。 ... [详细]
  • 尽管我们尽最大努力,任何软件开发过程中都难免会出现缺陷。为了更有效地提升对支持部门的协助与支撑,本文探讨了多种策略和最佳实践,旨在通过改进沟通、增强培训和支持流程来减少这些缺陷的影响,并提高整体服务质量和客户满意度。 ... [详细]
  • 本文探讨了 Kafka 集群的高效部署与优化策略。首先介绍了 Kafka 的下载与安装步骤,包括从官方网站获取最新版本的压缩包并进行解压。随后详细讨论了集群配置的最佳实践,涵盖节点选择、网络优化和性能调优等方面,旨在提升系统的稳定性和处理能力。此外,还提供了常见的故障排查方法和监控方案,帮助运维人员更好地管理和维护 Kafka 集群。 ... [详细]
  • PHP网站日志深度解析与数据洞察分析
    通过对PHP网站日志进行深入解析与数据洞察分析,可以有效提升网站性能和用户体验。由于网站日志数据量庞大,通常需要借助专业的日志分析工具来处理。常用的工具包括光年日志分析工具和WebLog Expert等,这些工具能够帮助技术人员快速识别并解决网站运行中的各种问题,从而优化SEO效果和提升整体运营效率。 ... [详细]
  • 基于Java的客户关系管理(CRM)系统优化与应用
    本研究探讨了基于Java技术的客户关系管理(CRM)系统的优化与应用。首先介绍了CRM系统的概念及其分类,并详细阐述了企业项目开发的流程。随后,对CRM系统的模块进行了划分,包括系统功能模块图和各模块的具体功能描述,为系统的高效运行提供了理论和技术支持。 ... [详细]
author-avatar
撩人的东莞博文
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有