springboot集成Lean Cloud 及时通讯_cloud和boot通信-程序员宅基地

技术标签: java  及时通讯  

文档: https://leancloud.cn/docs/index.html#%E5%8D%B3%E6%97%B6%E9%80%9A%E8%AE%AF
1.先安装SDK
在这里插入图片描述

在这里插入图片描述
我java开发,选择maven引入

<dependency>
    <groupId>cn.leancloud</groupId>
    <artifactId>realtime-core</artifactId>
    <version>8.2.0</version>
</dependency>

java平台初始化代码,我是springboot项目,在启动类中写的

package com.mine.lean_cloud;

import cn.leancloud.LCException;
import cn.leancloud.LCLogger;
import cn.leancloud.callback.LCCallback;
import cn.leancloud.core.LeanCloud;
import cn.leancloud.im.v2.LCIMMessageManager;
import cn.leancloud.session.LCConnectionManager;
import com.mine.lean_cloud.controller.CustomConversationEventHandler;
import com.mine.lean_cloud.controller.CustomMessageHandler;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LeanCloudApplication {
	
    public static final String appId = "自己的appid";
    public static final String appKey = "自己的appidappkey";
    public static final String serverUrl = "自己的severUrl";

    public static void main(String[] args) {
        SpringApplication.run(LeanCloudApplication.class, args);
        start();
    }

    public static void start() {
        // 1.初始化SDK
        // 开启LC的调试日志
        //LeanCloud.setLogLevel(LCLogger.Level.DEBUG);
        // 及时通讯初始化
        LeanCloud.initialize(appId, appKey, serverUrl);
        // 建立长链接
        LCConnectionManager.getInstance().startConnection(new LCCallback() {
            @Override
            protected void internalDone0(Object o, LCException e) {
                if (e == null) {
                    System.out.println("成功建立 WebSocke 链接");
                } else {
                    System.out.println("建立 WebSocke 链接失败: " + e.getMessage());
                }
            }
        });

        // 设置全局的对话事件处理 handler
        LCIMMessageManager.setConversationEventHandler(new CustomConversationEventHandler());
        // 设置全局的消息处理 handler
        LCIMMessageManager.registerDefaultMessageHandler(new CustomMessageHandler());
    }

}

获取 appId,appKey,serverUrl
在这里插入图片描述
SDK文档https://leancloud.cn/docs/realtime-guide-beginner.html
代码编写:
注意:一下接口中发送消息没有用第三方restApi,因为调用有次数限制(120次/分钟),但是使用SDK没有限制

package com.mine.lean_cloud.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.leancloud.LCFile;
import cn.leancloud.im.v2.*;
import cn.leancloud.im.v2.callback.*;
import cn.leancloud.im.v2.messages.LCIMImageMessage;
import cn.leancloud.im.v2.messages.LCIMTextMessage;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mine.lean_cloud.IMConstants;
import com.mine.lean_cloud.domain.AjaxResult;
import com.mine.lean_cloud.domain.IMConversation;
import com.mine.lean_cloud.domain.IMMessage;
import com.mine.lean_cloud.util.IMRestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * desc:
 *
 * @author qts
 * @date 2021/11/26 0026 上午 11:44
 */
@RestController
@RequestMapping("/LC")
public class StartController {

    private static final Logger log = LoggerFactory.getLogger(StartController.class);

	// 没有用
    /**
     * 创建对话,返回对话信息 √
     */
    @PostMapping("/createConversation2")
    public Object createConversation2(@RequestBody IMConversation conversation) {

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("name",conversation.getName() );
        params.put("m",conversation.getMembers() );
        params.put("unique",conversation.getUnique() );
        params.put("attr",conversation.getAttributes() );
        JSONObject jsonObject = IMRestUtil.imPost(ContentType.JSON.getValue(), params, IMConstants.CONVERSATION_URL);

        // 封装返回数据
        IMConversation result = new IMConversation();
        result.setCreateTime(DateUtil.parseUTC(jsonObject.get("createdAt").toString()));
        result.setUpdateTime(DateUtil.parseUTC(jsonObject.get("updatedAt").toString()));
        result.setUnique((Boolean) jsonObject.get("unique"));
        result.setName((jsonObject.get("name")).toString());
        result.setConversationId((jsonObject.get("objectId")).toString());
        result.setMembers(JSON.parseArray(jsonObject.get("m").toString(),String.class));
        result.setAttributes((jsonObject.get("attr")));
        return result;
    }


    /**
     * 对话列表 √
     */
    @GetMapping("/conversationList")
    public List<IMConversation> conversationList(IMConversation conversation) {

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("skip",conversation.getSkip() );// 跳过几条数据
        params.put("limit",conversation.getLimit() );// 条数
        params.put("where", "{\"m\":\""+conversation.getMembers().get(0)+"\"}");// 指定成员ID
        params.put("order","-createdAt" );// 创建时间倒序


        String jsonStr = IMRestUtil.imGet(null, params, IMConstants.CONVERSATION_URL+"?skip={skip}&limit={limit}&where={where}&order={order}");
        JSONObject jsonObject = JSON.parseObject(jsonStr);
        JSONArray list = jsonObject.getJSONArray("results");

        // 封装返回数据
        List<IMConversation> resultList = new ArrayList<IMConversation>();
        list.forEach(e -> {
            IMConversation result = new IMConversation();
            JSONObject object = JSON.parseObject(e.toString());

            result.setCreateTime(DateUtil.parseUTC(object.get("createdAt").toString()));
            result.setUpdateTime(DateUtil.parseUTC(object.get("updatedAt").toString()));
            result.setUnique((Boolean) object.get("unique"));
            result.setName((object.get("name")).toString());
            result.setConversationId((object.get("objectId")).toString());
            result.setMembers(JSON.parseArray(object.get("m").toString(),String.class));
            result.setAttributes((object.get("attr")));

            resultList.add(result);
        });

        return resultList;
    }

	//发送消息没有用第三方restApi,因为调用有次数限制(120次/分钟),但是使用SDK没有限制
    /**
     * 发送消息 √ 文本消息/图片消息
     * @ 指定人, @所有人
     * @param message
     * @return
     */
    @PostMapping("/sendMsg")
    public String sendMsg(@RequestBody IMMessage message) {
        LCIMClient client = LCIMClient.getInstance(message.getClientId());

        LCIMMessage msg;

        if (StrUtil.isEmpty(message.getImgPath())) {
            // 发送文本消息

            if (StrUtil.isEmpty(message.getText())) {
                return "消息内容不能为空";
            }
            msg = new LCIMTextMessage();
            // 消息内容
            ((LCIMTextMessage) msg).setText(message.getText());
            // 自定义属性
            ((LCIMTextMessage) msg).setAttrs(message.getAttributes());
        } else {
            // 发送图片消息

            LCFile file = new LCFile(message.getImgName(),message.getImgPath(), null);
            msg = new LCIMImageMessage(file);
            // 消息内容
            ((LCIMImageMessage) msg).setText(message.getText());
            // 自定义属性
            ((LCIMImageMessage) msg).setAttrs(message.getAttributes());
        }

        // @ 成员列表
        if (CollUtil.isNotEmpty(message.getMentionList())) {
            msg.setMentionList(message.getMentionList());
        }
        // @ 所有人
        if (null != message.getMentionAll()) {
            msg.setMentionAll(message.getMentionAll());
        }

        // 发送消息
        LCIMConversation conversation = client.getConversation(message.getConversationId());
        conversation.sendMessage(msg, new LCIMConversationCallback() {
            @Override
            public void done(LCIMException e) {
                if (e == null) {
                    log.info("消息发送成功!");
                } else {
                    if (msg instanceof LCIMTextMessage) {
                        log.error(String.format("消息发送失败:【发送人为】:%s,【内容为】:%s,【接收对话ID】:%s,【错误原因】:%s",msg.getFrom(),((LCIMTextMessage) msg).getText(),msg.getConversationId(),e.getMessage()));
                    } else if (msg instanceof LCIMImageMessage) {
                        log.error(String.format("消息发送失败:【发送人为】:%s,【内容为】:%s,【接收对话ID】:%s,【错误原因】:%s",msg.getFrom(),((LCIMImageMessage) msg).getText(),msg.getConversationId(),e.getMessage()));
                    }
                }
            }
        });
        return "发送成功";
    }

    /**
     * 查询对话成员列表,用于@成员是的下拉框
     */
    @GetMapping("/memberList")
    public Object memberList(@RequestHeader("projectId") Long projectId, IMConversation conversation) {
        // 校验参数
        if (StrUtil.isEmpty(conversation.getConversationId())) {
            return "对话ID不能为空";
        }
        //调用第三方restApi
        String body = IMRestUtil.imGet(null, null, IMConstants.CONVERSATION_URL +"/"+ conversation.getConversationId() + "/members");
        JSONArray resultList = JSON.parseObject(body).getJSONArray("result");
        if (null == resultList) {
            return "对话中没有成员或对话不存在 ! ";
        }
        //处理userId
        List<Long> list = new ArrayList<Long>();
        resultList.forEach(clientId -> list.add(Long.valueOf(clientId.toString().substring(clientId.toString().indexOf("_")+1))));

        // todo 通过 用户ID查询昵称,

        return list;
    }

    /**
     * 历史消息列表 ,前端用sdk查,restApi没有attr字段,服务查询自定义属性
     */
    @Deprecated
    @GetMapping("/msgList")
    public List<IMConversation> msgList(IMMessage message) {

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("limit",message.getLimit() );// 条数

        String jsonStr = IMRestUtil.imGet(
            ContentType.JSON.getValue()
            , params,
            IMConstants.CONVERSATION_URL+"/"+message.getConversationId()
                + "/messages?limit={limit}");
        JSONArray list = JSON.parseArray(jsonStr);

        // 封装返回数据
        List<IMConversation> resultList = new ArrayList<IMConversation>();


        return resultList;
    }



    //===================================================================================================

    /**
     * 登录
     * @param clientId
     * @return
     */
    @GetMapping("/login")
    public String login(String clientId) {
        // 登录成功后,登录LC
        // Tom 创建了一个 client,用自己的名字作为 clientId 登录
        LCIMClient client = LCIMClient.getInstance(clientId);
        loginLC(client);

        return clientId+"登录成功";
    }

    /**
     * 退出登录
     * @param clientId
     * @return
     */
    @GetMapping("/logout")
    public String logout(String clientId) {
        // 登录成功后,登录LC
        // Tom 创建了一个 client,用自己的名字作为 clientId 登录
        LCIMClient client = LCIMClient.getInstance(clientId);
        logoutLC(client);

        return clientId+"登出成功";
    }

    /**
     * 创建对话单聊/多聊 √ 后端调用SDK 所需参数在回调函数中,无法返回给前端,故需要前端自己调用SDK
     * @param clientId 当前用户ID
     * @param userIds 指定用户ID
     * @return
     */
    @Deprecated
    @PostMapping("/createConversation")
    public String createConversation(String clientId, String[] userIds, @RequestBody(required = false) Object attributes) {
        LCIMClient client = LCIMClient.getInstance(clientId);
        // System.out.println(JSONUtil.toJsonStr(attributes));
        Map<String, Object> attr = null;
        if (null != attributes) {
            attr = new HashMap<String, Object>(1);
            //attributes.put("attributes", JSONUtil.toJsonStr(attributes));// 转为字符串
            attr.put("attributes", attributes);// 构建信息
        }

        client.createConversation(Arrays.asList(userIds), String.join(" & ",userIds)+" & friends", attr, false, true,
            new LCIMConversationCreatedCallback() {
                @Override
                public void done(LCIMConversation conversation, LCIMException e) {
                    if (e == null) {
                        // 创建成功
                        System.out.println("对话ID: "+ conversation.getConversationId());
                        System.out.println(conversation.toString());
                    }else {
                        System.out.println("对话创建失败: code为"+e.getAppCode());
                    }
                }
            });

        return "创建对话成功";
    }

    /**
     * 添加成员
     *
     * @param conversation
     * @return
     */
    @PostMapping("/addMember")
    public String addMember(@RequestBody IMConversation conversation) {
        LCIMClient client = LCIMClient.getInstance(conversation.getClientId());
        // 首先根据 ID 获取 Conversation 实例
        final LCIMConversation conv = client.getConversation(conversation.getConversationId());

        // 邀请 Mary 加入对话
        conv.addMembers(conversation.getMembers(), new LCIMOperationPartiallySucceededCallback() {
            @Override
            public void done(LCIMException e, List<String> successfulClientIds, List<LCIMOperationFailure> failures) {
                // 添加成功
                if (e == null) {

                    System.out.println("添加成功,成员有: " + String.join(",", successfulClientIds));
                    System.out.println("添加失败,成员有: " + failures.toString());
                } else {
                    System.out.println(e.getAppCode());
                }
            }
        });
        return "添加成员成功";
    }

    /**
     * 查询包含自己的对话,返回不了前端数据
     * @param clientId
     * @return
     */
    @GetMapping("/getMyConversation")
    public String getMyConversation(String clientId) {
        LCIMClient client = LCIMClient.getInstance(clientId);
        LCIMConversationsQuery query = client.getConversationsQuery();
        // 执行查询
        query.findInBackground(new LCIMConversationQueryCallback(){
            @Override
            public void done(List<LCIMConversation> convs,LCIMException e){
                if(e == null){
                    // convs 就是想要的结果
                    convs.forEach(System.out::println);
                }
            }
        });
        return clientId+": 查询包含自己的对话";
    }

    /**
     * 查询对话中的历史消息,返回不了前端数据,故前端自己调用SDK
     * @param clientId
     * @param conversationId
     * @return
     */
    @GetMapping("/getHistoryMsg")
    public String getHistoryMsg(String clientId,String conversationId,Integer limit) {
        LCIMClient client = LCIMClient.getInstance(clientId);
        LCIMConversation conversation = client.getConversation(conversationId);
        // limit 取值范围 1~100,如调用 queryMessages 时不带 limit 参数,默认获取 20 条消息记录
        conversation.queryMessages(limit, new LCIMMessagesQueryCallback() {
            @Override
            public void done(List<LCIMMessage> messages, LCIMException e) {
                if (e == null) {
                    // 成功获取最新 10 条消息记录
                    messages.forEach(message ->{
                        if (message instanceof LCIMTextMessage) {
                            System.out.println("文本消息: "+client.getClientId()+"收到来自: "+message.getFrom()+"的消息,内容为: "+((LCIMTextMessage) message).getText()
                                +",自定义参数为: "+ ((LCIMTextMessage) message).getAttrs()
                            );
                        } else {
                            System.out.println("其他消息: "+client.getClientId()+"收到来自: "+message.getFrom()+"的消息,内容为: "+message.getContent());
                        }
                    });
                }
            }
        });
        return clientId+": 查询历史消息";
    }

    // ===================================================================================================================

    /**
     * 登录LC
     */
    private void loginLC(LCIMClient client) {

        // Tom 登录
        client.open(new LCIMClientCallback() {
            @Override
            public void done(LCIMClient client, LCIMException e) {
                if (e == null) {
                    // 成功打开连接
                    System.out.println(client.getClientId()+"成功登录LC服务");
                }
            }
        });

    }

    /**
     * 退出LC
     */
    private void logoutLC(LCIMClient client) {

        client.close(new LCIMClientCallback(){
            @Override
            public void done(LCIMClient client,LCIMException e){
                if(e==null){
                    // 登出成功
                    System.out.println(client.getClientId()+"成功退出LC服务");
                }
            }
        });

    }

}

IMConstants

package com.mine.lean_cloud;

/**
 * desc: IM 常量
 *
 * @author qts
 * @date 2021/12/3 0003 上午 10:41
 */
public class IMConstants {


    public static final String APP_ID = "自己的appId";
    public static final String APP_KEY = "自己的appKey";
    public static final String MASTER_KEY = "自己的masterKey";
    /**
     * 服务器url
     */
    public static final String SERVER_URL = "自己的apiUrl地址";
    /**
     * 对话CRUD的url
     */
    public static final String CONVERSATION_URL = "/1.2/rtm/conversations";


}

IMConversation

package com.mine.lean_cloud.domain;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * desc: 对话数据
 *
 * @author qts
 * @date 2021/11/30 0030 下午 4:36
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class IMConversation {

    /**
     * 对话名
     */
    private String name;

    /**
     * 成员ID列表
     */
    List<String> members;//members
    /**
     * 对话ID
     */
    private String conversationId;
    /**
     * 创建者ID
     */
    private String creator;//creator
    /**
     * 客户ID
     */
    private String clientId;
    /**
     * 自定义属性
     */
    private Object attributes;
    /**
     * 标记根据成员原子创建的对话,对话唯一
     */
    private Boolean unique = true;
    /**
     * 创建时间
     */
    @JsonFormat( timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;
    /**
     * 修改时间
     */
    @JsonFormat( timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;

    private Integer skip = 0;

    private Integer limit = 10;
}

IMMessage

package com.mine.lean_cloud.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;
import java.util.Map;

/**
 * desc: 消息数据
 *
 * @author qts
 * @date 2021/11/30 0030 下午 3:47
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class IMMessage {

    /**
     * 文本消息
     */
    private String text;

    /**
     * 图片地址
     */
    private String imgPath;

    /**
     * 图片名称
     */
    private String imgName;

    /**
     * 对话ID
     */
    private String conversationId;

    /**
     * 客户ID,发送人用户ID,格式:"项目ID_userId"
     */
    private String clientId;
    /**
     * 自定义属性
     */
    private Map<String, Object> attributes;

    /**
     * @ 成员列表
     */
    private List<String> mentionList;
    /**
     * @ 所有人
     */
    private Boolean mentionAll;

    private Integer limit = 20;

    @JsonIgnore
    public Integer getLimit() {
        return limit;
    }
    @JsonProperty
    public void setLimit(Integer limit) {
        this.limit = limit;
    }

}

IMRestUtil

package com.mine.lean_cloud.util;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mine.lean_cloud.IMConstants;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

/**
 * desc: IM rest Api 请求工具
 *
 * @author qts
 * @date 2021/12/3 0003 上午 11:09
 */
public class IMRestUtil {

    private static final RestTemplate restTemplate = RestTemplateUtil.getInstance();

    /**
     * im post 请求
     * @param contentType
     * @param params 请求参数
     * @param modelUrl 模块url
     * @return
     */
    public static JSONObject imPost(String contentType, Map<String, Object> params, String modelUrl) {
        HttpHeaders headers = new HttpHeaders();
        headers.add("X-LC-Id", IMConstants.APP_ID);
        headers.add("X-LC-Key", IMConstants.MASTER_KEY+",master");
        if (StrUtil.isNotEmpty(contentType)) {
            headers.add("Content-Type", contentType);
        }

        //MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
        HttpEntity<Object> httpEntity = new HttpEntity<Object>(params, headers);
        //String urlParams = url + "?params={json}";
        ResponseEntity<String> responseEntity = restTemplate.exchange(IMConstants.SERVER_URL+modelUrl, HttpMethod.POST, httpEntity, String.class);
        return JSON.parseObject(responseEntity.getBody());
    }

    /**
     * im get 请求
     * @param contentType
     * @param params 请求参数,没有参数,随便传一个
     * @param modelUrl 模块url
     * @return
     */
    public static String imGet(String contentType, Map<String, Object> params, String modelUrl) {
        HttpHeaders headers = new HttpHeaders();
        headers.add("X-LC-Id", IMConstants.APP_ID);
        headers.add("X-LC-Key", IMConstants.MASTER_KEY+",master");
        if (StrUtil.isNotEmpty(contentType)) {
            headers.add("Content-Type", contentType);
        }

        //MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
        HttpEntity<Object> httpEntity = new HttpEntity<Object>(null, headers);
        //String urlParams = url + "?params={json}";
        ResponseEntity<String> responseEntity;
        if (params == null) {
            responseEntity = restTemplate.exchange(IMConstants.SERVER_URL + modelUrl, HttpMethod.GET, httpEntity, String.class);
        } else {
            responseEntity = restTemplate.exchange(IMConstants.SERVER_URL+modelUrl, HttpMethod.GET, httpEntity, String.class,params);
        }
        return responseEntity.getBody();
    }
}

RestTemplateUtil

package com.mine.lean_cloud.util;

import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.util.List;

/**
 * desc:
 *
 * @author qts
 * @date 2021/12/3 0003 上午 11:47
 */
public class RestTemplateUtil {

    private static final RestTemplate restTemplate = new RestTemplate();

    private RestTemplateUtil() {
    }

    public static RestTemplate getInstance() {
        //-----此处是 解决乱码 start-----
        List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
        //移除StringHttpMessageConverter
        converterList.remove(1);
        HttpMessageConverter<?> converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
        //convert顺序错误会导致失败
        converterList.add(1, converter);
//        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
//        converterList.add(fastJsonHttpMessageConverter);
        restTemplate.setMessageConverters(converterList);
        //-----此处是  解决乱码 end----------
        return restTemplate;
    }
}

CustomConversationEventHandler 自定义对话事件处理器

package com.mine.lean_cloud.controller;

import cn.leancloud.core.LeanCloud;
import cn.leancloud.im.v2.LCIMClient;
import cn.leancloud.im.v2.LCIMConversation;
import cn.leancloud.im.v2.LCIMConversationEventHandler;

import java.util.List;

/**
 * desc: 用于处理对话的各种事件
 *
 * @author qts
 * @date 2021/11/29 0029 下午 2:23
 */
public class CustomConversationEventHandler extends LCIMConversationEventHandler {

    /**
     * 实现本方法以处理聊天对话中的参与者离开事件
     *
     * @param client
     * @param conversation
     * @param members 离开的参与者
     * @param kickedBy 离开事件的发动者,有可能是离开的参与者本身
     * @since 3.0
     */
    @Override
    public void onMemberLeft(LCIMClient client,
                             LCIMConversation conversation, List<String> members, String kickedBy) {
    }

    /**
     * 实现本方法以处理聊天对话中的参与者加入事件
     *
     * @param client
     * @param conversation
     * @param members 加入的参与者
     * @param invitedBy 加入事件的邀请人,有可能是加入的参与者本身
     * @since 3.0
     */
    @Override
    public void onMemberJoined(LCIMClient client, LCIMConversation conversation, List<String> members, String invitedBy) {

    }

    /**
     * 实现本方法来处理当前用户被踢出某个聊天对话事件
     *
     * @param client
     * @param conversation
     * @param kickedBy 踢出你的人
     * @since 3.0
     */
    @Override
    public void onKicked(LCIMClient client, LCIMConversation conversation, String kickedBy) {

    }

    @Override
    public void onInvited(LCIMClient lcimClient, LCIMConversation lcimConversation, String operator) {
        // 当前 clientId被邀请到对话,执行此处逻辑
        System.out.println(lcimClient.getClientId()+ "被邀请");
    }
}

CustomMessageHandler 自定义消息处理器

package com.mine.lean_cloud.controller;

import cn.leancloud.im.v2.LCIMClient;
import cn.leancloud.im.v2.LCIMConversation;
import cn.leancloud.im.v2.LCIMMessage;
import cn.leancloud.im.v2.LCIMMessageHandler;
import cn.leancloud.im.v2.messages.LCIMImageMessage;
import cn.leancloud.im.v2.messages.LCIMTextMessage;

/**
 * desc: 通过定制自己的消息事件 Handler 处理服务端下发的消息通知
 *
 * @author qts
 * @date 2021/11/29 0029 下午 2:27
 */
public class CustomMessageHandler extends LCIMMessageHandler {

    /**
     * 重载此方法来处理接收消息
     *
     * @param message
     * @param conversation
     * @param client
     */
    @Override
    public void onMessage(LCIMMessage message, LCIMConversation conversation, LCIMClient client){
        if (message instanceof LCIMTextMessage) {
            System.out.println("文本消息: "+client.getClientId()+"收到来自: "+message.getFrom()+"的消息,内容为: "+((LCIMTextMessage) message).getText()
                +",自定义参数为: "+ ((LCIMTextMessage) message).getAttrs()
            );
        } else if (message instanceof LCIMImageMessage) {
            System.out.println("文本消息: "+client.getClientId()+"收到来自: "+message.getFrom()+"的消息,内容为: "+((LCIMImageMessage) message).getText()
                +",自定义参数为: "+ ((LCIMImageMessage) message).getAttrs()
            );
        } else {
            System.out.println("其他消息: " + client.getClientId() + "收到来自: " + message.getFrom() + "的消息,内容为: " + message.getContent());
        }

    }
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.mine</groupId>
    <artifactId>lean_cloud</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>lean_cloud</name>
    <description>Demo project for Spring Boot</description>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Mysql驱动包 -->
        <!--<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.6.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>

        <!-- LeanCloud 及时通讯-->
        <dependency>
            <groupId>cn.leancloud</groupId>
            <artifactId>realtime-core</artifactId>
            <version>8.2.0</version>
        </dependency>
    </dependencies>

    <!--<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>-->

</project>

测试:
一.消息发送和接收流程
1.调用登录方法,在服务端登录(实际登录请求直接前端调用SDK,在用户端登录,保持于LC的websocket链接)
前端SDK文档:https://leancloud.cn/docs/realtime-guide-beginner.html#hash1795902530
2.创建对话指定clientId(创建人ID),和聊天成员,对话名称
3.调用发送消息方法
4.在自定义消息处理器(CustomMessageHandler)中定义的处理接收方法:会打印在控制台(实际应该前端定义接收消息的回调,在前端接收对应的消息),此处只做的后端的测试
前端SDK文档:https://leancloud.cn/docs/realtime-guide-beginner.html#hash785732056
二.其他接口
本例只简单实现发送消息(文本/图片),@成员,接收消息,对话列表,消息历史记录,测回消息(由前端实现,因为后端测回的成功与否是在回调中展示的,如果出错,没法返回到前端,故前端调用,如果出错,可以响应个客户,同时前端处理了撤回消息的事件,对话中的每个成员都能收到相应的提示)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44684303/article/details/121762752

智能推荐

5个超厉害的资源搜索网站,每一款都可以让你的资源满满!_最全资源搜索引擎-程序员宅基地

文章浏览阅读1.6w次,点赞8次,收藏41次。生活中我们无时不刻不都要在网站搜索资源,但就是缺少一个趁手的资源搜索网站,如果有一个比较好的资源搜索网站可以帮助我们节省一大半时间!今天小编在这里为大家分享5款超厉害的资源搜索网站,每一款都可以让你的资源丰富精彩!网盘传奇一款最有效的网盘资源搜索网站你还在为找网站里面的资源而烦恼找不到什么合适的工具而烦恼吗?这款网站传奇网站汇聚了4853w个资源,并且它每一天都会持续更新资源;..._最全资源搜索引擎

Book类的设计(Java)_6-1 book类的设计java-程序员宅基地

文章浏览阅读4.5k次,点赞5次,收藏18次。阅读测试程序,设计一个Book类。函数接口定义:class Book{}该类有 四个私有属性 分别是 书籍名称、 价格、 作者、 出版年份,以及相应的set 与get方法;该类有一个含有四个参数的构造方法,这四个参数依次是 书籍名称、 价格、 作者、 出版年份 。裁判测试程序样例:import java.util.*;public class Main { public static void main(String[] args) { List <Book>_6-1 book类的设计java

基于微信小程序的校园导航小程序设计与实现_校园导航微信小程序系统的设计与实现-程序员宅基地

文章浏览阅读613次,点赞28次,收藏27次。相比于以前的传统手工管理方式,智能化的管理方式可以大幅降低学校的运营人员成本,实现了校园导航的标准化、制度化、程序化的管理,有效地防止了校园导航的随意管理,提高了信息的处理速度和精确度,能够及时、准确地查询和修正建筑速看等信息。课题主要采用微信小程序、SpringBoot架构技术,前端以小程序页面呈现给学生,结合后台java语言使页面更加完善,后台使用MySQL数据库进行数据存储。微信小程序主要包括学生信息、校园简介、建筑速看、系统信息等功能,从而实现智能化的管理方式,提高工作效率。

有状态和无状态登录

传统上用户登陆状态会以 Session 的形式保存在服务器上,而 Session ID 则保存在前端的 Cookie 中;而使用 JWT 以后,用户的认证信息将会以 Token 的形式保存在前端,服务器不需要保存任何的用户状态,这也就是为什么 JWT 被称为无状态登陆的原因,无状态登陆最大的优势就是完美支持分布式部署,可以使用一个 Token 发送给不同的服务器,而所有的服务器都会返回同样的结果。有状态和无状态最大的区别就是服务端会不会保存客户端的信息。

九大角度全方位对比Android、iOS开发_ios 开发角度-程序员宅基地

文章浏览阅读784次。发表于10小时前| 2674次阅读| 来源TechCrunch| 19 条评论| 作者Jon EvansiOSAndroid应用开发产品编程语言JavaObjective-C摘要:即便Android市场份额已经超过80%,对于开发者来说,使用哪一个平台做开发仍然很难选择。本文从开发环境、配置、UX设计、语言、API、网络、分享、碎片化、发布等九个方面把Android和iOS_ios 开发角度

搜索引擎的发展历史

搜索引擎的发展历史可以追溯到20世纪90年代初,随着互联网的快速发展和信息量的急剧增加,人们开始感受到了获取和管理信息的挑战。这些阶段展示了搜索引擎在技术和商业模式上的不断演进,以满足用户对信息获取的不断增长的需求。

随便推点

控制对象的特性_控制对象特性-程序员宅基地

文章浏览阅读990次。对象特性是指控制对象的输出参数和输入参数之间的相互作用规律。放大系数K描述控制对象特性的静态特性参数。它的意义是:输出量的变化量和输入量的变化量之比。时间常数T当输入量发生变化后,所引起输出量变化的快慢。(动态参数) ..._控制对象特性

FRP搭建内网穿透(亲测有效)_locyanfrp-程序员宅基地

文章浏览阅读5.7w次,点赞50次,收藏276次。FRP搭建内网穿透1.概述:frp可以通过有公网IP的的服务器将内网的主机暴露给互联网,从而实现通过外网能直接访问到内网主机;frp有服务端和客户端,服务端需要装在有公网ip的服务器上,客户端装在内网主机上。2.简单的图解:3.准备工作:1.一个域名(www.test.xyz)2.一台有公网IP的服务器(阿里云、腾讯云等都行)3.一台内网主机4.下载frp,选择适合的版本下载解压如下:我这里服务器端和客户端都放在了/usr/local/frp/目录下4.执行命令# 服务器端给执_locyanfrp

UVA 12534 - Binary Matrix 2 (网络流‘最小费用最大流’ZKW)_uva12534-程序员宅基地

文章浏览阅读687次。题目:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=93745#problem/A题意:给出r*c的01矩阵,可以翻转格子使得0表成1,1变成0,求出最小的步数使得每一行中1的个数相等,每一列中1的个数相等。思路:网络流。容量可以保证每一行和每一列的1的个数相等,费用可以算出最小步数。行向列建边,如果该格子是_uva12534

免费SSL证书_csdn alphassl免费申请-程序员宅基地

文章浏览阅读504次。1、Let's Encrypt 90天,支持泛域名2、Buypass:https://www.buypass.com/ssl/resources/go-ssl-technical-specification6个月,单域名3、AlwaysOnSLL:https://alwaysonssl.com/ 1年,单域名 可参考蜗牛(wn789)4、TrustAsia5、Alpha..._csdn alphassl免费申请

测试算法的性能(以选择排序为例)_算法性能测试-程序员宅基地

文章浏览阅读1.6k次。测试算法的性能 很多时候我们需要对算法的性能进行测试,最简单的方式是看算法在特定的数据集上的执行时间,简单的测试算法性能的函数实现见testSort()。【思想】:用clock_t计算某排序算法所需的时间,(endTime - startTime)/ CLOCKS_PER_SEC来表示执行了多少秒。【关于宏CLOCKS_PER_SEC】:以下摘自百度百科,“CLOCKS_PE_算法性能测试

Lane Detection_lanedetectionlite-程序员宅基地

文章浏览阅读1.2k次。fromhttps://towardsdatascience.com/finding-lane-lines-simple-pipeline-for-lane-detection-d02b62e7572bIdentifying lanes of the road is very common task that human driver performs. This is important ..._lanedetectionlite

推荐文章

热门文章

相关标签