socket.io实现简易聊天室功能

本文简单介绍使用websocket实现一个简单的聊天室功能,我这里是用vite初始化的vue3项目。

在线体验地址:http://chat.lb0125.com/chat

需要安装的库:

socket.io、socket.io-client等

1、代码

整体代码目录结构如下,分为客户端和服务端代码:

 

1.1、服务端代码chat_server

a、首先使用 npm init  初始化一个node工程

b、然后npm install socket.io

c、新建一个app.js文件,代码如下:

const { createServer } = require("http");
const { Server } = require("socket.io");

const httpServer = createServer();
const io = new Server(httpServer, {
  cors: {                 //解决跨域问题
    origin: "*",
    methods: ["GET", "POST"]
  }
});

io.on("connection", (socket, data) => {
  // 接受消息
  socket.on('sendMsg', (data) => {
    // io表示广播出去,发送给全部的连接
    io.emit('sendMsged', data)
  });

  // 接受登录事件
  socket.on('login', data => {
    io.emit('logined', data)
  })

  // 接受登出事件
  socket.on('logout', data => {
    io.emit('logouted', data)
  })

  // 监听客户端与服务端断开连接
  socket.on('disconnecting', () => {
    console.log('客户端断开了连接')
  })
});

httpServer.listen(3011, function () {
  console.log('http://localhost:3011')
});

1.2、客户端代码 chat_client

由于我这里还使用安装了vue-router4、element-plus、less-loader moment等库,当然您可以根据自己需要决定是否安装

 

 

 

第一步:初始化vue3+vite项目

  npm create vite@latest 后 根据提示输入项目名称,选择vue版本进行后续操作

第二步:npm install socket.io-client以及其他需要使用到的库

第三步:添加环境配置文件,修改vite.config.js配置以及编写代码

a、vite.config.js:

import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
//引入gzip静态资源压缩
import viteCompression from 'vite-plugin-compression'
const path = require('path');
const { resolve } = require('path');

export default ({ mode,command }) => {
  console.log('当前环境=========' + mode)
  const plugins = [
    vue(),
  ];
  // 如果是非开发环境,配置按需导入element-plus组件
  if (mode !== 'development') {
    plugins.push(
      AutoImport({
        resolvers: [ElementPlusResolver()],
      })
    );
    plugins.push(
      Components({
        resolvers: [ElementPlusResolver()],
      })
    );
  }

  return defineConfig({
    base: './',
    plugins,
    hmr: { overlay: false },

    // 配置前端服务地址和端口(可注释掉,默认是localhost:3000)
    server: {
      host: '0.0.0.0',
      port: 9000,
      // 是否开启 http
      http: false,
      // 本地跨域代理
      proxy: {
        '/***': {
          target:'http://****',
          changeOrigin: true,
        },
      }
    },

    // 起个别名,在引用资源时,可以用‘@/资源路径’直接访问
    resolve: {
      alias: {
        "@": resolve(__dirname, "src"),
      },
    },

    css: {
      preprocessorOptions: {
        less: {
          modifyVars: {
            hack: `true; @import (reference) "${path.resolve("src/assets/css/base.less")}";`,
          },
          javascriptEnabled: true,
        },
      },
    },

    // 打包配置
    build: {
      minify: 'terser',
      terserOptions: {
        compress: {
          drop_console: true, // 清除console
          drop_debugger: true, // 清除debugger
        },
      },
      chunkSizeWarningLimit: 1500, // 大文件报警阈值设置
      rollupOptions: {
        output: {
          chunkFileNames: 'static/js/[name]-[hash].js',
          entryFileNames: 'static/js/[name]-[hash].js',
          assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
          // 超大静态资源拆分
          manualChunks(id) {
            if (id.includes('node_modules')) {
              let str = id.toString().split('node_modules/')[1].split('/')[0].toString();
              return str.substring(str.lastIndexOf('@') + 1);
            }
          }
        }
      }
    }
  })
}

b、表情图片放置在chat_client/public/imgs/face目录下:

 

 

 c、在src/common目录下新建constant.js文件:

/**
 * 常量
 */

// 是否是开发环境
export const isDev = import.meta.env.VITE_APP_ENV == "development" ? true : false;

// 当前所属环境
export const env = import.meta.env.VITE_APP_ENV;

// api地址
export const baseUrl = import.meta.env.VITE_APP_BASEURL;
export const wsUrl = import.meta.env.VITE_WS_URL;

// 表情
export const faceImgs = [
  { img: 'weixiao.png', name: '[微笑]' },
  { img: 'yukuai.png', name: '[愉快]' },
  { img: 'aoman.png', name: '[傲慢]' },
  { img: 'baiyan.png', name: '[白眼]' },
  { img: 'ciya.png', name: '[呲牙]' },
  { img: 'daku.png', name: '[大哭]' },
  { img: 'deyi.png', name: '[得意]' },
  { img: 'fadai.png', name: '[发呆]' },
  { img: 'fanu.png', name: '[发怒]' },
  { img: 'ganga.png', name: '[尴尬]' },
  { img: 'haixiu.png', name: '[害羞]' },
  { img: 'jie.png', name: '[饥饿]' },
  { img: 'jingkong.png', name: '[惊恐]' },
  { img: 'jingya.png', name: '[惊讶]' },
  { img: 'lenghan.png', name: '[冷汗]' },
  { img: 'liulei.png', name: '[流泪]' },
  { img: 'nanguo.png', name: '[难过]' },
  { img: 'piezui.png', name: '[撇嘴]' },
  { img: 'se.png', name: '[色]' },
  { img: 'shui.png', name: '[睡]' },
  { img: 'tiaopi.png', name: '[调皮]' },
  { img: 'touxiao.png', name: '[偷笑]' },
  { img: 'zhuakuang.png', name: '[抓狂]' },
]

e、在src/views目录下新建chat文件夹,并在chat文件夹下新建Chat.vue文件

<template>
  <div class="container">
    <div class="header"
      :style="{ 'border-bottom': isMobile ? '1px solid #eee' : '0 none', padding: isMobile ? '0 12px' : '0px' }">
      <el-button type="primary" @click="onConnect" v-if="userName == ''">进入会话</el-button>
      <span v-else style="flex:1;">您的姓名:{{ userName }}</span>
      <el-button @click="onDisConnect" v-show="userName !== ''">退出会话</el-button>
    </div>
    <div class="content" id="content" @click="() => { isShowFace = false }"
      :style="{ border: isMobile ? 'none' : '1px solid #eee' }">
      <ul>
        <li v-for="(item, i) in msgList" :key="i">
          <p v-if="item.type == 0" class="item content-login">{{ item.date }} {{
            item.userId == userId ? '您' :
            item.userName
          }}{{ item.msg }}</p>
          <p v-if="item.type == -1" class="item content-logout">{{ item.date }} {{
            item.userId == userId ? '您' :
            item.userName
          }}{{ item.msg }}</p>
          <div v-if="item.type == 1" class="item" :class="{ 'text-right': userId == item.userId }">
            <!-- 自己发送的消息 -->
            <div v-if="item.userId == userId" class="clearfix">
              <div class="content-name" style="text-align:right;">
                <span style="margin-right:10px;">{{ item.date }}</span>
                <span>{{ item.userName }}</span>
              </div>
              <div class="content-msg right" style="text-align: right;">
                <p style="display:inline-block;text-align:left;border-top-right-radius: 0px;background: #73e273;"
                  v-html="item.msg"></p>
              </div>
            </div>
            <!-- 别人发送的消息 -->
            <div v-else>
              <div class="content-name">
                <span>{{ item.userName }}</span>
                <span style="margin-left:10px;">{{ item.date }}</span>
              </div>
              <div class="content-msg" style="text-align: left;">
                <p style="display:inline-block;text-align:left;border-top-left-radius: 0px;" v-html="item.msg"></p>
              </div>
            </div>
          </div>
        </li>
      </ul>
    </div>
    <div class="footer" :style="{ padding: isMobile ? '10px 12px' : '10px 0px' }">
      <el-input class="content-input" type="textarea" :autosize="{ minRows: 1, maxRows: 5 }" resize="none" v-model="msg"
        ref="inputRef" placeholder="请输入发送内容" @focus="onInputFocus" @keyup.enter="onSend" />
      <div class="face-icon">
        <img src="@/assets/img/face.png" alt="表情" @click="onToggleFace">
      </div>
      <div class="send-dv">
        <el-button type="primary" class="send-btn" @click="onSend" :disabled="userName == ''">发 送</el-button>
      </div>
    </div>
    <div class="face-dv" v-show="isShowFace" :class="{ 'face-dv-pc': !isMobile }">
      <div class="arrow" v-show="!isMobile"></div>
      <div class="face">
        <div class="face-item" v-for="item in faceImgs" :key="item.img" @click="onInputFace(item.img, item.name)">
          <img :src="`./imgs/face/${item.img}`" />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'chat'
}
</script>
<script setup>
import { onMounted, ref, reactive, nextTick } from "vue"
import moment from 'moment'
import { ElMessage, ElMessageBox } from 'element-plus'
import { io } from 'socket.io-client';
import { wsUrl, faceImgs } from '@/common/constant';
import { isPC, guid } from '@/utils/utils';

const isMobile = ref(!isPC());
const isShowFace = ref(false);
const inputRef = ref(null);
const msg = ref('')
const userId = ref(''); // 用户id
const userName = ref('');  // 用户姓名
let socket = null;

const abc = ref('<span>asdf</span>')
const msgList = reactive(
  [
    // { id: 0, type: 1, userName: '张安', date: '2012-12-12 12:12:12', msg: '哈哈哈1' },
    // { id: 1, type: 0, userName: '张安1', date: '2012-12-12 12:12:12', msg: '张安进入会话' },
    // { id: 2, type: 1, userName: '张安2', date: '2012-12-12 12:12:12', msg: '哈哈哈3' },
  ]
)

// 表情框显示隐藏切换
const onToggleFace = () => {
  if (userName.value == '') {
    ElMessage.warning('请先点击进入会话');
    return;
  }
  if (isShowFace.value) {
    isShowFace.value = false;
  } else {
    isShowFace.value = true;
  }

}

// 输入框获取焦点事件
const onInputFocus = (e) => {
  isShowFace.value = false;
  if (userName.value == '') {
    ElMessage.warning('请先点击进入会话');
  }
}

// 点击表情
const onInputFace = (img, name) => {
  console.log(img, name)
  msg.value += name;
  isShowFace.value = false;
}

// 点击发送消息
const onSend = () => {
  if (msg.value.trim() == '') {
    ElMessage.warning('不可以发送空白消息')
    return
  }
  let str = msg.value;
  faceImgs.forEach(item => {
    if (str.indexOf(item.name) > -1) {
      str = str.replaceAll(item.name, `<img src="./imgs/face/${item.img}" style="width:20px;vertical-align:top;" />`);
    }
  })
  socket.emit('sendMsg', {
    type: 1,
    userId: userId.value,
    userName: userName.value,
    date: moment(new Date()).format('HH:mm:ss'),
    msg: str
  })
  msg.value = '';
  isShowFace.value = false;
}

const onConnect = () => {
  console.log('onConnect')
  ElMessageBox.prompt('请输入您的姓名', '提示', {
    confirmButtonText: '确 认',
    cancelButtonText: '取 消',
    inputPattern: /^[\s\S]*.*[^\s][\s\S]*$/,
    inputErrorMessage: '你的姓名',
  }).then(({ value }) => {
    userId.value = guid();
    userName.value = value;
    socket = io.connect(wsUrl);
    setTimeout(() => {
      socket.emit('login', {
        id: Math.random() * 100000000,
        type: 0,
        date: moment(new Date()).format('HH:mm:ss'),
        userId: userId.value,
        userName: userName.value
      })
    }, 200)

    socket.on('connect', () => {
      console.log('客户端建立连接'); // true
    });

    // 监听登录事件
    socket.on('logined', data => {
      msgList.push({
        id: Math.random() * 100000000,
        type: data.type,
        userId: data.userId,
        userName: data.userName,
        date: data.date,
        msg: ' 进入会话'
      })
    })

    // 监听登录出事件
    socket.on('logouted', data => {
      msgList.push({
        id: Math.random() * 100000000,
        type: data.type,
        userId: data.userId,
        userName: data.userName,
        date: data.date,
        msg: '离开会话'
      })
    })

    // 监听发送消息事件
    socket.on('sendMsged', data => {
      msgList.push({
        id: Math.random() * 100000000,
        type: data.type,
        userId: data.userId,
        userName: data.userName,
        date: data.date,
        msg: data.msg
      })
      nextTick(() => {
        let contentNode = document.getElementById('content')
        contentNode.scrollTop = contentNode.scrollHeight
      })
    })
  }).catch(() => {

  })
}

const onDisConnect = () => {
  console.log('onDisConnect')
  socket.emit('logout', {
    id: Math.random() * 100000000,
    type: -1,
    date: moment(new Date()).format('HH:mm:ss'),
    userId: userId.value,
    userName: userName.value
  })
  setTimeout(() => {
    socket.disconnect()
    userId.value = '';
    userName.value = '';
  }, 200)
}

</script>

<style lang="less" scoped>
.container {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  max-width: 522px;
  margin: 0px auto;

  .header {
    height: 50px;
    display: flex;
    align-items: center;
    border-bottom: 1px solid #eee;
  }

  .content {
    flex: 1;
    padding: 12px;
    overflow-y: auto;

    .item {
      margin-bottom: 20px;

      &.content-login {
        font-size: 12px;
        color: #666;
        text-align: center;
      }

      &.content-logout {
        font-size: 12px;
        color: #666;
        text-align: center;
      }
    }

    .content-name {
      font-size: 12px;
      color: #666;
      margin-bottom: 5px;
    }

    .content-msg {
      width: 90%;
      word-break: break-word;
      font-size: 16px;

      p {
        padding: 8px 10px;
        background: #eee;
        border-radius: 8px;
        color: #232323;
      }
    }

  }

  .footer {
    display: flex;
    align-items: end;

    .content-input {
      flex: 1
    }

    .face-icon {
      position: relative;
      width: 56px;
      height: 100%;

      img {
        position: absolute;
        width: 26px;
        height: 26px;
        left: 17px;
        bottom: 4px;
      }
    }

    .send-dv {
      position: relative;
      width: 60px;
      height: 100%;

      .send-btn {
        position: absolute;
        width: 100%;
        height: 34px;
        left: 0;
        bottom: 0;
      }
    }

  }

  .face-dv {
    height: 150px;
    background: #eee;

    &.face-dv-pc {
      position: absolute;
      width: 100%;
      left: 0px;
      bottom: 53px;
    }

    .arrow {
      position: absolute;
      bottom: -20px;
      right: 75px;
      width: 0;
      height: 0;
      border: 10px solid;
      border-color: #eee transparent transparent transparent;
    }

    .face {
      width: 100%;
      height: 100%;
      padding: 4px;
      overflow: auto;

      .face-item {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 34px;
        height: 34px;
        margin: 6px;
        border-radius: 4px;
        &:hover {
          background: #ced8d5;
        }

        img {
          width: 27px;
          height: 27px;
        }
      }
    }
  }
}

::-webkit-scrollbar {
  /*滚动条整体样式*/
  width: 4px;
  /*高宽分别对应横竖滚动条的尺寸*/
  height: 4px;
}

::-webkit-scrollbar-thumb {
  /*滚动条里面小方块*/
  border-radius: 3px;
  background: #1c1e2038;
}

:deep(.el-textarea__inner) {
  min-height: 34px !important;
}

:deep(.el-textarea__inner) {
  font-size: 16px;
  // 隐藏滚动条
  scrollbar-width: none;
  /* firefox */
  -ms-overflow-style: none;

  /* IE 10+ */
  &::-webkit-scrollbar {
    display: none;
    /* Chrome Safari */
  }
}</style>

注意:上面Chat.vue文件里引入了utils/utils文件里的isPC和guid方法,这两个方法分别是用来判断当前是否是pc端和生成uuid的。

2、效果图

 

 

3、部署代码到服务器

最后分别把客户端代码和服务端代码部署到服务器上就可以玩耍了

需要购买阿里云产品和服务的,点击此链接可以领取优惠券红包,优惠购买哦,领取后一个月内有效: http://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=fp9ccf07

 

本文转载于网络 如有侵权请联系删除

相关文章

  • es7学习笔记 cpu负载不均衡、超长fullGC、大量400报错[通俗易懂]

    大家好,又见面了,我是你们的朋友全栈君。现象:往es7集群中推数时,发生如下情况接口出现很多400发现集群中某台机器cpu被怼爆发生fullGC产生400报错的原因是es7做了熔断优化,当jvm内存使用超过阈值,为了避免丑陋的oom,会直接限流并抛出EsRejectedExecutionException。我们强硬的关掉了这个配置,因为我们的推数有失败重试。产生fullGC是因为一个bulk批处理的数据量太大,我们一个文档1.5M,800个文档作为一批,两个线程并行推,jvm内存30G,所以es服务器很快就开始进行fullGC。所以我们立刻将bulk的数量调整为50,并改为单线程推送,终于没有出现fullGC。bulk会把将要处理的数据载入内存中,所以数据量是有限制的,最佳的数据量不是一个确定的数值,它取决于你的硬件,你的文档大小以及复杂性,你的索引以及搜索的负载。 一般建议是1000-5000个文档,如果你的文档很大,可以适当减少队列,大小建议是5-15MB,默认不能超过100M,可以在es的配置文件(即$ES_HOME下的config下的elasticsearch.yml)中。 产

  • php – cURL从重定向获取url

    大家好,又见面了,我是全栈君。我目前正在使用cURL尝试从网站刮刀的重定向获取URL.我只需要网站上的网址.我在过去几天研究过stackoverflow和其他网站,但都没有成功.我目前使用的代码来自这个网站:$url="http://www.someredirect.com"; $ch=curl_init($url); curl_setopt($ch,CURLOPT_USERAGENT,'Mozilla/5.0(Windows;U;WindowsNT5.1;en-US;rv:1.8.1.1)Gecko/20061204Firefox/2.0.0.1'); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); curl_setopt($ch,CURLOPT_HEADER,true); curl_setopt($ch,CURLOPT_FOLLOWLOCATION,false); curl_setopt($ch,CURLOPT_NOBODY,true); $response=curl_exec($ch); preg

  • 一次调试去了解redis集群的slot机制

    某次我在压测redis集群(该redis集群使用一批intel性能硬件aep),为了上线前摸清性能上限。于是就有了后面的故事。正常情况下,因为我没有那么多机器去打redis集群,于是去寻求测试部门压测平台的帮助,去获取到大流量(为了尽量模拟真实线上,使用了旁路录制的流量进行重放),但是由于压测平台是对业务服务的(请求pb格式是业务定制的),而没有这种redis的读写压测功能。所以还是得靠服务,但是服务机器我旁路测试环境又没有多台。于是就有了大数据同学的建议,你们的数据可不可以都打到同一台slot。好吧这个redis的slot有耳闻,但是还不是特别了解,因为平时的连接我只需要一个url+端口就搞定了。比如以下配置于是乎,使用gdb打开服务进程,去内部窥探下slot是怎么运作的gdb--args./SearchUserFeatureServer--flagfile=conf/gflags.conf设置好断点,可以按r,开始探索之旅首先我发现初始化连接的时候,redis会响应,返回类似这种连接信息f2a9484ec91a9007863d015e2f72146940477efb10.194.8

  • Spock单元测试框架以及在美团优选的实践

    总第465篇2021年第035篇Spock是国外一款优秀的测试框架,基于BDD(行为驱动开发)思想实现,功能非常强大。Spock结合Groovy动态语言的特点,提供了各种标签,并采用简单、通用、结构化的描述语言,让编写测试代码更加简洁、高效。目前,美团优选物流绝大部分后端服务已经采用了Spock作为测试框架,在开发效率、可读性和维护性方面均取得了不错的收益。1.背景2.Spock是什么?和JUnit、jMock有什么区别?3.使用Spock解决单元测试开发中的痛点4.Mock模拟5.异常测试6.Spock静态方法测试7.动态Mock静态方法8.覆盖率9.DAO层测试作者简介1.背景XML之父TimBray最近在博客里有个好玩的说法:“代码不写测试就像上了厕所不洗手……单元测试是对软件未来的一项必不可少的投资。”具体来说,单元测试有哪些收益呢?它是最容易保证代码覆盖率达到100%的测试。可以⼤幅降低上线时的紧张指数。单元测试能更快地发现问题(见下图左)。单元测试的性价比最高,因为错误发现的越晚,修复它的成本就越高,而且难度呈指数式增长,所以我们要尽早地进行测试(见下图右)。编码人员,一般

  • 面试官:Tomcat 的调优怎么做?你的最佳实践有哪些?

    你知道的越多,不知道的就越多,业余的像一棵小草!你来,我们一起精进!你不来,我和你的竞争对手一起精进! 编辑:业余草来源:segmentfault.com/a/1190000015918707推荐:https://www.xttblog.com/?p=5107前言Tomcat作为Web应用的服务器,目前绝大多数公司都是用其作为应用服务器的,应用服务器的执行效率会影响系统执行,这里会讲Tomcat怎样进行配置能提高处理性能。另外必须提到对应的JVM参数的优化的一些经验。Tomcat运行模式分三种模式:bio,nio,apr一般使用nio模式。bio效率低,apr对系统配置有一些比较高的要求。接下来,需要我们确认一下自己线上的Tomcat运行模式。查看配置文件server.xml<Executorname="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="1024" minSpareThreads="512" prestartminSpa

  • 数据分析的目的和意义(作用)是什么?

    很多人会问数据分析目的是什么?它有什么作用?让我们看看亿信华辰如何看待数据分析的目的和意义。仅仅谈论数据分析的作用实际上并不重要,因此在谈论该作用之前,我们首先要考虑受众,打个比方:对于个人而言,由于身体感应设备的原因,让我们每天锻炼身体健身各种指标可以数字化,最终完成对个人身体和生活习惯的自我量化,然后完善对个人日常生活规律的调节,使我们过上更好的生活。数据分析目的数据分析目的1:分类检查未知分类或暂时未知分类的数据,目的是预测数据属于哪个类别或属于哪个类别。使用具有已知分类的相似数据来研究分类规则,然后将这些规则应用于未知分类数据。数据分析目的2:预测预测是指对数字连续变量而不是分类变量的预测。数据分析目的3:关联规则和推荐系统关联规则或关联分析是指在诸如捆绑之类的大型数据库中找到一般的关联模式。在线推荐系统使用协作过滤算法,该协作过滤算法是基于给定的历史购买行为,等级,浏览历史或任何其他可测量的偏好行为或什至其他用户购买历史的方法。协同过滤可在单个用户级别生成“购买时可以购买的东西”的购买建议。因此,在许多推荐系统中使用了协作过滤,以向具有广泛偏好的用户提供个性化推荐。数据分析目

  • 批量预测转录因子(TF)和转录因子结合位点(TFBS)

    在真核生物中,基因的编码序列在DNA链上是不连续的,被非编码序列隔开。这些基因,只有在转录因子结合到其特定的DNA序列上后,基因才开始表达。那么,我们要了解的是,什么是转录因子?什么又是转录因子结合的的特定的DNA序列(转录因子结合位点)?那首先,什么是转录因子呢?维基百科中是这么说的:转录因子(Transcriptionfactor)是指能够结合在某基因上游特异核苷酸序列上的蛋白质,这些蛋白质能调控其基因的转录。方法是转录因子可以调控核糖核酸聚合酶(RNA聚合酶,或叫RNA合成酶)与DNA模板的结合。转录因子的本质是与DNA特异性结合的一系列蛋白质。一般有不同的功能区域,如DNA结合结构域与效应结构域。转录因子不单与基因上游的启动子区域结合,也可以和其它转录因子形成转录因子复合体来影响基因的转录,可以产生很复杂而精细的影响。结合在DNA上的启动子以及增强子之类控制转录的区域上,促进或者抑制DNA上的遗传信息向RNA转录的过程。什么又是转录因子结合位点?某度百科中是这么介绍的:转录因子结合位点(Transcriptionfactorbindingsite,TFBS)是与转录因子结合的D

  • CRM呼叫中心和社交媒体集成的技术实现

    版权声明:本文为博主汪子熙原创文章,未经博主允许不得转载。https://jerry.blog.csdn.net/article/details/89839798只需要在这里加一个很简单的badiimplementation就能让我们的socialmediaitem显示在inbox的searchresult里面。选中某个socialmedia点toolbar的displaybutton希望跳转到我们的socialmediadetailUI的做法:Framework首先会call一个generic的display方法,bol_entity就是我们的socialmediaBOLentity。用这个badi实现navigationlink的determination:如果我们需要重用inboxtoolbar上的其他标准button,道理类似:到前一封邮件提到的superclass去找generic实现的method,到里面去找badicall的地方。PS:有的button实现里没有badi,比如forward的实现,是取BOL的root->BTOrderHeader->BTHea

  • Windows Linux Mac 路由添加删除

     1.Windows10.204网段是内网网段,192.168网段是用来上外网的 ipconfig/all set/pchoice=请输入可以上网的网卡网关,如果没有则输入IP地址: routedelete0.0.0.0 routedelete10.204.0.0 routeadd10.204.0.0mask255.255.0.010.204.35.1 routeadd0.0.0.0mask0.0.0.0%choice%复制2.Mac公网网关:10.4.95.191 内网网关:192.168.1.1 要访问的内网地址:10.204.0.0 sudoroutedelete10.4.95.191 sudoroutedelete10.204.0.0 sudoroute-nadddefault10.4.95.191 sudoroute-nadd-net10.204.0.0-netmask255.255.0.0192.168.1.1复制3.Linux

  • jeklly+Github pages 添加评论

    之前的个人博客主要是fork了其他人的源码。基于Jekyll+Githubpages。在此基础上改了一些东西,适合自己的才是最好的嘛。最后才准备做评论这方面的东西。 disqus 先去http://www.disqus.com/注册了username,修改了相关了html文件。讲道理是可以用的,评论框在文章页面一直加载不出来,过一会又会出现reload。我是在访问外国网站啊,讲道理不应该。作为一个二把手又看了一遍源码,什么也没看出来。只好放弃disqus。 多说 这个就算不访问外国网站也该可以了吧。先去注册搞到了username,http://duoshuo.com再根据源码,添加多说评论。 comments_provider:duoshuo duoshuo_username:x-nicolo复制 再根据多说给的代码粘贴到模板代码里: <!--多说评论框start--> <divclass="ds-thread"data-thread-key="请将此处替换成文章在你的站点中的ID"data-title="请替换成文章

  • 最新5篇生成对抗网络相关论文推荐—FusedGAN、DeblurGAN、AdvGAN、CipherGAN、MMD GANS

    【导读】专知内容组整理了最近生成对抗网络相关文章,为大家进行介绍,欢迎查看!1.Semi-supervisedFusedGANforConditionalImageGeneration(基于半监督FusedGAN的条件图像生成)作者:NavaneethBodla,GangHua,RamaChellappa摘要:WepresentFusedGAN,adeepnetworkforconditionalimagesynthesiswithcontrollablesamplingofdiverseimages.Fidelity,diversityandcontrollablesamplingarethemainqualitymeasuresofagoodimagegenerationmodel.Mostexistingmodelsareinsufficientinallthreeaspects.TheFusedGANcanperformcontrollablesamplingofdiverseimageswithveryhighfidelity.Wearguethatcontrollabili

  • 腾讯云TDSQLMySQL版创建DCDB分布式实例分布式数据库

    1.接口描述接口请求域名:dcdb.tencentcloudapi.com。 本接口(CreateDCDBInstance)用于创建包年包月的云数据库实例,可通过传入实例规格、数据库版本号、购买时长等信息创建云数据库实例。 默认接口请求频率限制:20次/秒。 APIExplorer提供了在线调用、签名验证、SDK代码生成和快速检索接口等能力。您可查看每次调用的请求内容和返回结果以及自动生成SDK调用示例。 2.输入参数以下请求参数列表仅列出了接口请求参数和部分公共参数,完整公共参数列表见公共请求参数。 参数名称 必选 类型 描述 Action 是 String 公共参数,本接口取值:CreateDCDBInstance。 Version 是 String 公共参数,本接口取值:2018-04-11。 Region 是 String 公共参数,详见产品支持的地域列表。 Zones.N 是 ArrayofString 分片节点可用区分布,最多可填两个可用区。当分片规格为一主两从时,其中两个节点在第一个可用区。注意当前可售卖的可用区需要通过Desc

  • 《1024伐木累》-屌丝、快播、苍老师

    本周的伐木累故事,耗仔可谓是晴天间日,找到了未来的曙光,耗仔相信,只要有信念,每个人都有机会成功! 每周都有很多的大事发生,这周也不例外,或许在这个先进的媒体时代,你觉得什么都不稀奇,或许在这个自媒体的年月,你觉得自己才是主角,敲起愤怒的键盘,一起批判、一起向往,闲暇之余乐一乐,然后赶紧用代码改变世界去! 1.碰瓷儿 绝对可以相信,之前的两个都是丽姐派来的   2.规律生活 你。。。多大了   3.屌丝 穷屌,穷屌的。。。   4.快播不平 我真想快点把你拨下去!   5.苍老师 在学习电路的时候,我知道这就叫做串联,连起来啦~   作者:耗仔 首发:ITIBB公众号 声明:《1024伐木累》系列为作者原创,ITIBB

  • 常用数据结构之数组

    1.背景 数组是最最基本的数据存储方式 数据结构从根本来看其实就2中数组和链表其他都是在这两种的基础上扩展出来的比如:队列-数组链表都能实现栈-数组链表都能实现哈希表-数组和队列实现树-链表实现图-数组实现 基于数组是java中的基础,很多童鞋都是学习过的,这里这是简单的整理一下,让课程结构完整! 2.代码 packagecom.ldp.course.structure.demo01Array; importcom.ldp.course.common.MyArrayUtil; importorg.junit.Test; importjava.util.Arrays; /** *@create06/296:50 *@description<p> *数据结构与算法之数组 *课件: *https://www.cnblogs.com/newAndHui/p/16421890.html * *</p> */ publicclassTest01Array{ /** *一维数组测试 */ @Test publicvoidtest01(){ int[]arr

  • 【洛谷 P4525】 【模板】自适应辛普森法 1

    自适应辛普森法,用于求定积分。 原理是不断二分区间直到区间的积分和二次函数的积分拟合程度足够高,然后用二次函数的积分值来代替原积分值。 #include<bits/stdc++.h> #definelowbit(x)(x&(-x)) #definepbpush_back #definerep(i,m,n)for(inti=(m);i<=(n);++i) #definedop(i,m,n)for(inti=(m);i>=(n);--i) #defineall(x)x.begin(),x.end() #defineOpen(s)freopen(s,"r",stdin); #defineWrite(s)freopen(s,"w",stdout); usingnamespacestd; typedeflonglongll; template<classT>voidchkmin(T&a,Tb){if(a>b)a=b;} template<classT>voidchkmax(T&a,Tb){if(a<b)a=b;}

  • 05-2. 念数字(15)

    输入一个整数,输出每个数字对应的拼音。当整数为负数时,先输出“fu”字。十个数字对应的拼音如下: 0:ling 1:yi 2:er 3:san 4:si 5:wu 6:liu 7:qi 8:ba 9:jiu 复制   输入格式: 输入在一行中给出一个整数,如: 1234 。 提示:整数包括负数、零和正数。 输出格式: 在一行中输出这个整数对应的拼音,每个数字的拼音之间用空格分开,行末没有最后的空格。如 yiersansi。 输入样例: -600 复制 输出样例: fuliulingling复制 1#include<stdio.h> 2 3intmain() 4{ 5intn; 6scanf("%d",&n); 7 8if(n<0){ 9printf("fu"); 10n=-n; 11} 12intt=n,mask=1; 13while(t>9){ 14t/=10; 15mask*=10; 16} 17char*s[]={"ling","yi","er","san","si","wu","liu","qi","ba

  • Java调用XML的方法:DocumentBuilderFactory

      (1)首先得到:得到 DOM 解析器的工厂实例 DocumentBuilderFactory domfac=DocumentBuilderFactory.newInstance();   (2)然后从 DOM 工厂获得 DOM 解析器   DocumentBuilder dombuilder=domfac.newDocumentBuilder();   (3)把要解析的 XML 文档转化为输入流,以便 DOM 解析器解析它   InputStream is= new  FileInputStream("test1.xml");           (4)解析 XML 文档的输入流,得到一个 Document    Document&nbs

  • 字符统计

    统计字符的个数 输出:每行显示字符的种类和个数 #include<stdio.h> intmain() { charc; intnumber=0,space=0,chinese=0,a[50]={0},i,j; for(j=0;c!='\n';j++) { scanf("%c",&c); if(c>='a'&&c<='z') a[c-'a']++; elseif(c>='A'&&c<='Z') a[c-'A']++; elseif(c=='') space++; elseif(c>='0'&&c<='9') number++; else chinese++; } for(i=0;i<50;i++) { if(a[i]!=0) printf("%c=%d\n",i+'a',a[i]);//mind } printf("space=%d\nnumber=%d\nchinese=%d\n",space,number,chinese/2); return0; }复制  

  • 使用qiankun搭建微服务 (通信部分)2

    本章介绍一下qiankun的主和子应用之间的通信,原理其实是发布订阅模式,类似vue的eventbus,首先主和子应用里面都要有一个初始化的action,如下: import{initGlobalState}from"qiankun"; /** *初始的state */ conststate={ name:"child-app", msg:"子应用消息", }; /** *初始化本应用全局的state */ constaction=initGlobalState(state); export{action};复制 此时只需要在发送和接收的地方使用这个action就可以了,代码如下: <template> <divclass="hello"> <inputtype="text"v-model="context"/> <button@click="clickHandler">发送消息到主应用</button> </div> </template> <script> import{a

  • 链接记录

    常用的jar包 下载  

  • 用python爬取豆瓣电影Top 250

      首先,打开豆瓣电影Top250,然后进行网页分析。找到它的Host和User-agent,并保存下来。  然后,我们通过翻页,查看各页面的url,发现规律:   第一页:https://movie.douban.com/top250?start=0&filter=   第二页:https://movie.douban.com/top250?start=25&filter=   第三页:https://movie.douban.com/top250?start=50&filter=     第四页:https://movie.douban.com/top250?start=75&filter=   我们发现,每个页面的url都是https://movie.douban.com/top250?start=+25+&filter=的规律。如此,就可以开始写代码: importrequests frombs4importBeautifulSoup defget_movie(): headers={ 'Host':'movie.d

相关推荐

推荐阅读