JAVA结合WebSocket实现简单客服聊天功能
说明:该示例只简单的实现了客服聊天功能。
1、聊天记录没有保存到数据库中,一旦服务重启,消息记录将会没有,如果需要保存到数据库中,可以扩展
2、页面样式用的网上模板,样式可以自己进行修改
3、只能由用户主要发起会话,管理员无法主动进行对话
4、页面之间跳转代码没有包含在里面,请自己书写,在管理员消息列表页中,需要把该咨询的用户ID带到客服回复页面中
5、${websocket_url} 这个为项目的URL地址
效果截图:
客服回复页面(member_admin_chat.html) |
管理员消息列表页(member_admin_chat_list.html) |
用户咨询页面(member_chat.html) |
代码:
页面所需要用到的基础样式、图片,下载链接:https://www.lanzous.com/ias1kcb (这个只是自己网上下载的样式demo,可以根据自己的来)
pom.xml
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
或者jar包
javax.websocket-api-1.0.jar
下载地址:https://yvioo.lanzous.com/i3AXkhl3s3c
配置类
WebSocketConfig.java
package com.config; import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;
import java.util.Set; public class WebSocketConfig implements ServerApplicationConfig {
@Override
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> endpointClasses) {
return null;
} @Override
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) { //在这里会把含有@ServerEndpoint注解的类扫描加载进来 ,可以在这里做过滤等操作 return scanned;
}
}
消息DTO类(使用了lombok,这里不在多做说明)
ChatDTO.java
package com.websocket.dto; import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors; /**
* @author 。
*/
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ChatDTO { /**
* 用户ID
*/
private String userId; /**
* 用户发送信息
*/
private String message; /**
* 发送日期
* 消息时间格式(yyyy-MM-dd)
*/
private String createDate; /**
* 发送时间
* 消息时间格式(yyyy-MM-dd HH:mm:ss)
*/
private String createTime; }
用户DTO类
ChatUserDTO.java
package com.websocket.dto; import com.entity.CmsUser;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors; /**
* @author 。
*/
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ChatUserDTO { /**
* 用户id
*/
private String userId; /**
* 用户名
*/
private String userName; /**
* 用户图片
*/
private String userImg; public ChatUserDTO convertUser(CmsUser user){
ChatUserDTO chatUserDTO=new ChatUserDTO();
chatUserDTO.setUserId(user.getId()+"")
.setUserName(user.getUsername())
.setUserImg(user.getUserImg());
return chatUserDTO;
}
}
ChatWebSocket.java
package com.websocket; import com.service.RedisService;
import com.util.DateFormatUtils;
import com.entity.CmsUser;
import com.manager.CmsUserMng;
import com.enums.ChatTypeEnum;
import com.websocket.Constants;
import com.websocket.dto.ChatDTO;
import com.websocket.dto.ChatUserDTO;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext; import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*; /**
* @author 。
*/
@ServerEndpoint(value = "/chat_websocket")
public class ChatWebSocket { private RedisService redisService; private CmsUserMng cmsUserMng; public ChatWebSocket() {
WebApplicationContext webctx = ContextLoader.getCurrentWebApplicationContext();
this.redisService = (RedisService) webctx.getBean("redisService");
this.cmsUserMng = (CmsUserMng) webctx.getBean("cmsUserMng");
} /**
* 存储用户id
*/
public static Map userMap = new HashMap(); /**
* 聊天记录
*/
public static Map chatRecordMap = new HashMap(); /**
* 管理员列表session
*/
public static Session adminSession; /**
* 创建
*
* @param session
*/
@OnOpen
public void onOpen(Session session) {
Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
List<String> strs = requestParameterMap.get("msg");
if (strs != null && strs.size() > 0) {
String json = strs.get(0);
//从聊天集中去掉该集合
JSONObject object = JSONObject.fromObject(json);
String userId = object.getString("user_id");
String chatType = object.getString("chat_type"); /*--------------管理员列表-----------------------*/
if (ChatTypeEnum.adminListChatType.getKey().equalsIgnoreCase(chatType)) {
adminSession = session;
List list = getUserList(userMap);
//遍历所有聊天用户集合的id
chat_list_show(adminSession, list);
return; } /*--------------管理员聊天框打开-----------------------*/
if (ChatTypeEnum.adminChatType.getKey().equalsIgnoreCase(chatType)) {
//从集合中获取用户对应的数据加入信息列表中
List sessions = (List) userMap.get(userId);
if (sessions == null) {
sessions = new ArrayList();
}
sessions.add(session);
userMap.put(userId, sessions); } /*--------------用户聊天框打开-----------------------*/
if (ChatTypeEnum.userChatType.getKey().equalsIgnoreCase(chatType)) {
//判断是否建立聊天通道
List sessions = (List) userMap.get(userId);
if (sessions == null) {
sessions = new ArrayList();
}
sessions.add(session);
userMap.put(userId, sessions); } //聊天记录信息存放
List chatRecords = (List) chatRecordMap.get(userId);
if (chatRecords != null) {
chat((List<Session>) userMap.get(userId), chatRecords);
} }
} /**
* 发送消息
*
* @param json {userId:'',message:'',create_time:'',create_date:'',chat_type:'admin_list/admin_chat/user_chat'}
* admin_list:表示客服列表数据请求
* admin_chat:表示客服回复页面请求
* user_chat表示用户消息页面请求
*
*
* @throws Exception
*/
@OnMessage
public void onMessage(Session session, String json) {
JSONObject object = JSONObject.fromObject(json);
//用户ID
String userId = object.getString("user_id");
//用户发送的信息
String message = object.getString("message");
//请求类型
String chatType = object.getString("chat_type"); /*--------------管理员聊天-----------------------*/
if (ChatTypeEnum.adminChatType.getKey().equalsIgnoreCase(chatType)) {
//把管理员加入用户建立的聊天管道中 //用户聊天
//封装请求参数,时间为当前时间
ChatDTO chatDTO = new ChatDTO();
//userId=0表示是客服的回复
chatDTO.setUserId("0")
.setMessage(message)
.setCreateDate(DateFormatUtils.formatDate(new Date()))
.setCreateTime(DateFormatUtils.formatDateTime(new Date()));
//聊天记录信息存放
List chatRecords = (List) chatRecordMap.get(userId);
if (chatRecords == null) {
chatRecords = new ArrayList();
}
chatRecords.add(JSONObject.fromObject(chatDTO));
chatRecordMap.put(userId, chatRecords);
chat((List<Session>) userMap.get(userId), chatRecords); }
/*--------------用户聊天-----------------------*/
if (ChatTypeEnum.userChatType.getKey().equalsIgnoreCase(chatType)) { //封装请求参数,时间为当前时间
ChatDTO chatDTO = new ChatDTO();
chatDTO.setUserId(userId)
.setMessage(message)
.setCreateDate(DateFormatUtils.formatDate(new Date()))
.setCreateTime(DateFormatUtils.formatDateTime(new Date()));
String key = chatDTO.getUserId(); //聊天记录信息存放
List chatRecords = (List) chatRecordMap.get(key);
if (chatRecords == null) {
chatRecords = new ArrayList();
}
chatRecords.add(JSONObject.fromObject(chatDTO));
chatRecordMap.put(key, chatRecords);
chat((List<Session>) userMap.get(key), chatRecords);
if (adminSession != null) {
List list = getUserList(userMap);
//遍历所有聊天用户集合的id
chat_list_show(adminSession, list); }
} } /**
* 关闭
*/
@OnClose
public void onClose(Session session) { Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
List<String> strs = requestParameterMap.get("msg");
if (strs != null && strs.size() > 0) {
String json = strs.get(0);
JSONObject object = JSONObject.fromObject(json);
String userId = object.getString("user_id");
String chatType = object.getString("chat_type"); /*--------------管理员聊天框关闭-----------------------*/
if (ChatTypeEnum.adminChatType.getKey().equalsIgnoreCase(chatType)) { } /*--------------用户聊天框关闭-----------------------*/
if (ChatTypeEnum.userChatType.getKey().equalsIgnoreCase(chatType)) { } } } /**
* 发生错误
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
} /**
* 消息广播
*
* @param sessions
* @param messages
*/
public void chat(List<Session> sessions, List messages) {
for (Iterator it = sessions.iterator(); it.hasNext(); ) {
Session session = (Session) it.next();
try {
if (session.isOpen()) {
//当当前会话没有被关闭 发送消息
session.getBasicRemote().sendText(JSONArray.fromObject(messages) + "");
}
} catch (IOException e) {
e.printStackTrace();
}
} } /**
* 聊天列表显示
*/
public void chat_list_show(Session session, List list) {
try {
if (session.isOpen()) {
//当当前会话没有被关闭 发送消息
session.getBasicRemote().sendText(JSONArray.fromObject(list) + "");
}
} catch (IOException e) {
e.printStackTrace();
} } /**
* 通过id获取用户数据
*
* @return
*/
public List getUserList(Map userMap) {
List list = new ArrayList();
for (Object str : userMap.keySet()) {
ChatUserDTO chatUserDTO = new ChatUserDTO();
CmsUser user = cmsUserMng.findById(Integer.valueOf(str + ""));
list.add(chatUserDTO.convertUser(user));
}
return list;
} }
聊天枚举类
ChatTypeEnum.java
package com.websocket;
/**
* @author 。
*/ public enum ChatTypeEnum { adminListChatType("admin_list", "管理员列表"),
adminChatType("admin_chat", "管理员聊天"),
userChatType("user_chat", "用户聊天"),
chatCountType("chat_count","消息数目"); private String key; public String value; ChatTypeEnum() {
} ChatTypeEnum(String key, String value) {
this.key = key;
this.value = value;
} public String getKey() {
return key;
} public void setKey(String key) {
this.key = key;
} public String getValue() {
return value;
} public void setValue(String value) {
this.value = value;
}
}
用户咨询页面
member_chat.html
1 <!doctype html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8"/>
5 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
6 <meta name="viewport"
7 content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
8 <title>客服咨询</title>
9 <link rel="stylesheet" type="text/css" href="/${res}/chat/css/chat.css"/>
10 <script src="/${res}/js/jquery.1.9.1.js"></script>
11 <script src="/${res}/chat/js/flexible.js"></script>
12 </head>
13 <body>
14
15
16 <header class="header">
17 <a class="back" href="javascript:history.back()"></a>
18 <h5 class="tit">客服</h5>
19 </header>
20 <div id="message">
21
22 </div>
23 <div id="footer">
24 <img src="/${res}/chat/images/hua.png" alt=""/>
25 <input class="my-input" type="text"/>
26 <p class="send">发送</p>
27 </div>
28 <script>
29
30 //聊天
31 var ws;
32 var obj = {
33 user_id: '${user.id}',
34 message: '',
35 chat_type: "user_chat"
36 }
37 var target = "ws:${websocket_url!}/chat_websocket?msg=" + encodeURI(JSON.stringify(obj));
38
39
40 var canSend = false;
41 $(function () {
42
43 //处理浏览器兼容性
44 if ('WebSocket' in window) {
45 ws = new WebSocket(target);
46 } else if ('MozWebSocket' in window) {
47 ws = new MozWebSocket(target);
48 } else {
49 alert('WebSocket is not supported by this browser.');
50 return;
51 }
52
53 ws.onopen = function () {
54
55 };
56 ws.onmessage = function (event) {
57 var data = JSON.parse(event.data);
58 console.log(data)
59 $('#message').html("");
60 for (var i = 0; i < data.length; i++) {
61 if (data[i].userId != '${user.id}') {
62 reply("/${res}/chat/images/touxiangm.png", data[i].message);
63 } else {
64 ask("/${res}/chat/images/touxiang.png", data[i].message);
65 }
66 }
67 };
68
69 ws.onclose = function (event) {
70 alert("连接断开,请重新刷新页面");
71 location.reload();
72 1
73 }
74 $('#footer').on('keyup', 'input', function () {
75 if ($(this).val().length > 0) {
76 $(this).next().css('background', '#114F8E').prop('disabled', true);
77 canSend = true;
78 } else {
79 $(this).next().css('background', '#ddd').prop('disabled', false);
80 canSend = false;
81 }
82 })
83 $('#footer .send').click(send)
84 $("#footer .my-input").keydown(function (e) {
85 if (e.keyCode == 13) {
86 return send();
87 }
88 });
89 })
90
91 /* 对方消息div */
92 function reply(headSrc, str) {
93 var html = "<div class='reply'><div class='msg'><img src=" + headSrc + " /><span class='name'>客服</span><p><i class='msg_input'></i>" + str + "</p></div></div>";
94 return upView(html);
95 }
96
97 /* 自己消息div */
98 function ask(headSrc, str) {
99 var html = "<div class='ask'><div class='msg'><img src=" + headSrc + " />" + "<p><i class='msg_input'></i>" + str + "</p></div></div>";
100 return upView(html);
101 }
102
103 function upView(html) {
104 var message = $('#message');
105 message.append(html);
106 var h = message.outerHeight() - window.innerHeight;
107 window.scrollTo(0, document.body.scrollHeight)
108 return;
109 }
110
111 function send() {
112 if (canSend) {
113 var input = $("#footer .my-input");
114 var val = input.val()
115 var obj = {
116 user_id: '${user.id}',
117 message: val,
118 chat_type: "user_chat"
119 }
120 ws.send(JSON.stringify(obj));
121 //ask("/${res}/chat/images/touxiangm.png", val);
122 input.val('');
123 }
124 }
125 </script>
126 </body>
127 </html>
管理员消息列表页
member_admin_chat_list.html
<!DOCTYPE html>
<html >
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,minimal-ui">
<title>聊天列表 - ${site.name}</title>
<script src="${resSys}/jquery.js" type="text/javascript"></script>
<script src="${resSys}/front.js" type="text/javascript"></script>
<link rel="stylesheet" href="/${res}/bootstrap/css/bootstrap.css">
<script src="/${res}/bootstrap/js/bootstrap.js"></script> <!--[if lt IE 9]>
<script src="/${res}/js/html5shiv.min.js"></script>
<script src="/${res}/js/respond.min.js"></script>
<![endif]--> </head> <style>
.list-group-item span{
margin-right: 10px;
}
</style> <body>
[#include "../file/file_nav.html" /] <div>
<ul class="list-group" id="userList">
<li class="list-group-item">
<img src="/${res}/chat/images/touxiang.png" alt=""/>
<span class="badge">14</span>
Cras justo odio
</li>
</ul>
</div> </body> <script> var ws;
var obj={
user_id:'',
message:'',
chat_type:"admin_list"
}
var target="ws:${websocket_url}/chat_websocket?msg="+encodeURI(JSON.stringify(obj)); $(function () { //处理浏览器兼容性
if ('WebSocket' in window) {
ws = new WebSocket(target);
} else if ('MozWebSocket' in window) {
ws = new MozWebSocket(target);
} else {
alert('WebSocket is not supported by this browser.');
return;
} ws.onmessage = function (event) {
var data=JSON.parse(event.data);
var html="";
if (data!=null&&data.length>0){
for (var i=0;i<data.length;i++){
var user=data[i];
html+="<a href='${base}/member/to_admin_chat_"+user.userId+".jspx'>"
html+="<li class='list-group-item'>";
html+="<img src='/${res}/chat/images/touxiang.png' />";
if (user.countmsg!=undefined){
html+="<span class='badge'>"+user.countmsg+"</span>"
}
html+=user.userName;
html+="</li>";
html+="</a>";
}
}else {
html="<li style='text-align: center'>没有消息</li>";
}
$("#userList").html(html); }; ws.onclose=function (event) { } })
</script>
</html>
管理员消息回复页面
member_admin_chat.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
<title>客服咨询</title>
<link rel="stylesheet" type="text/css" href="/${res}/chat/css/chat.css"/>
<script src="/${res}/js/jquery.1.9.1.js"></script>
<script src="/${res}/chat/js/flexible.js"></script>
</head>
<body> <header class="header">
<a class="back" href="javascript:history.back()"></a>
<h5 class="tit">客服</h5>
</header>
<div id="message"> </div>
<div id="footer">
<img src="/${res}/chat/images/hua.png" alt=""/>
<input class="my-input" type="text"/>
<p class="send">发送</p>
</div>
<script> //聊天
var ws;
var obj = {
user_id: '${user.id}',
message: '',
chat_type: "user_chat"
}
var target = "ws:${websocket_url!}/chat_websocket?msg=" + encodeURI(JSON.stringify(obj)); var canSend = false;
$(function () { //处理浏览器兼容性
if ('WebSocket' in window) {
ws = new WebSocket(target);
} else if ('MozWebSocket' in window) {
ws = new MozWebSocket(target);
} else {
alert('WebSocket is not supported by this browser.');
return;
} ws.onopen = function () { };
ws.onmessage = function (event) {
var data = JSON.parse(event.data);
console.log(data)
$('#message').html("");
for (var i = 0; i < data.length; i++) {
if (data[i].userId != '${user.id}') {
reply("/${res}/chat/images/touxiangm.png", data[i].message);
} else {
ask("/${res}/chat/images/touxiang.png", data[i].message);
}
}
}; ws.onclose = function (event) {
alert("连接断开,请重新刷新页面");
location.reload();
}
$('#footer').on('keyup', 'input', function () {
if ($(this).val().length > 0) {
$(this).next().css('background', '#114F8E').prop('disabled', true);
canSend = true;
} else {
$(this).next().css('background', '#ddd').prop('disabled', false);
canSend = false;
}
})
$('#footer .send').click(send)
$("#footer .my-input").keydown(function (e) {
if (e.keyCode == 13) {
return send();
}
});
}) /* 对方消息div */
function reply(headSrc, str) {
var html = "<div class='reply'><div class='msg'><img src=" + headSrc + " /><span class='name'>客服</span><p><i class='msg_input'></i>" + str + "</p></div></div>";
return upView(html);
} /* 自己消息div */
function ask(headSrc, str) {
var html = "<div class='ask'><div class='msg'><img src=" + headSrc + " />" + "<p><i class='msg_input'></i>" + str + "</p></div></div>";
return upView(html);
} function upView(html) {
var message = $('#message');
message.append(html);
var h = message.outerHeight() - window.innerHeight;
window.scrollTo(0, document.body.scrollHeight)
return;
} function send() {
if (canSend) {
var input = $("#footer .my-input");
var val = input.val()
var obj = {user_id: '${user.id}', message: val, chat_type: "user_chat"}
ws.send(JSON.stringify(obj));
//ask("/${res}/chat/images/touxiangm.png", val);
input.val('');
}
} </script>
</body>
</html>
JAVA结合WebSocket实现简单客服聊天功能的更多相关文章
- java 网站用户在线和客服聊天
注:本文来源于<java 网站用户在线和客服聊天> 这是应用到项目中的一个例子. 实现原理是将信息存储到Application域里面.然后使用Struts2 Action 用json格式的 ...
- springboot+websocket实现简单的在线聊天功能
效果如下: java实现逻辑: 1.引入maven依赖 <dependency> <groupId>org.springframework.boot</groupId&g ...
- 使用socket.io实现双向实时消息传递,(客服聊天功能)
思否 https://segmentfault.com/a/1190000010974426 博客园 https://www.cnblogs.com/limitcode/p/7845168.html ...
- ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(二) 实现聊天室连接
上一篇已经简单介绍了layim WebUI即时通讯组件和获取数据的后台方法.现在要讨论的是SingalR的内容,之前都是直接贴代码.那么在贴代码之前先分析一下业务模型,顺便简单讲一下SingalR里的 ...
- ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(四) 添加表情、群聊功能
休息了两天,还是决定把这个尾巴给收了.本篇是最后一篇,也算是草草收尾吧.今天要加上表情功能和群聊.基本上就差不多了,其他功能,读者可以自行扩展或者优化.至于我写的代码方面,自己也没去重构.好的,我们开 ...
- 转载 ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(三) 激动人心的时刻到啦,实现1v1聊天
ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(三) 激动人心的时刻到啦,实现1v1聊天 看起来挺简单,细节还是很多的,好,接上一篇,我们已经成功连接singalR服务器 ...
- 转载 ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(一) 整理基础数据
ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(一) 整理基础数据 最近碰巧发现一款比较好的Web即时通讯前端组件,layim,百度关键字即可,我下面要做的就是基于这个前 ...
- 基于PHP实现一个简单的在线聊天功能(轮询ajax )
基于PHP实现一个简单的在线聊天功能(轮询ajax ) 一.总结 1.用的轮询ajax 二.基于PHP实现一个简单的在线聊天功能 一直很想试着做一做这个有意思的功能,感觉复杂的不是数据交互和表结构,麻 ...
- 使用 jquery 的 上传文件插件 uploadify 3.1 配合 java 来做一个简单的文件上次功能。并且在界面上有radio 的选择内容也要上传
使用 jquery 的 上传文件插件 uploadify 3.1 配合 java 来做一个简单的文件上次功能.并且在界面上有radio 的选择内容也要上传 uploadify 插件的 下载和文档地址 ...
随机推荐
- LeeCode刷题笔记
(本来想在LeeCode题目页面上做注释的,结果没找到位置,只好来这里了) 字符串部分: 14.最长公共前缀:编写一个函数来查找字符串数组中的最长公共前缀. 示例 1: 输入: ["flow ...
- NECAT组装ONT long reads
NECAT 可用于ONT数据的纠错,组装,如果想对ONT long reads进行call SV,也可以使用necatsv. githup网址:https://github.com/xiaochuan ...
- Python文件复制shutil模块
Python中shutil模块主要用于文件操作,如复制,属性判断等 1.copyfileobj,拷贝文件内容,将文件句柄赋给该方法 def copyfileobj(src, dst, length=1 ...
- 错误笔记: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable) E: Unable to lock the administration di
亲测可用 --jack alexander@alexander-virtual-machine:~$ sudo apt-get install -y httpdE: Could not get loc ...
- C#页面缓存设置
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { Sessioninfo(); } Session.R ...
- mysql数据操作语言DML
插入insert 插入方式1 语法: insert into 表名(列名,....) values(值1,....) 说明: 1.插入的值的类型要与列的类型一致或兼容 2.可以为null的值:①列写了 ...
- adjective
形容词用来描述名词或代词:副词用来描述剩下的(动词.形容词.副词和整句).adverb: to word. Adjectives are used almost exclusively to modi ...
- C# 设计模式(1)——简单工厂模式、工厂模式、抽象工厂模式
1.前言 上一篇写了设计模式原则有助于我们开发程序的时候能写出高质量的代码(牵一发而不动全身),这个系列还是做个笔记温习一下各种设计模式,下面就看看简单工厂模式.工厂模式.抽象工厂模式. 2.简单工厂 ...
- C++中union相关
前两天做阿里笔试遇到一个选择题题目大概是 #include <iostream> #include <stdlib.h> using namespace std; union ...
- Handler与多线程
1.Handler介绍 在Android开发中,我们常会使用单独的线程来完成某些操作,比如用一个线程来完成从网络上下的图片,然后显示在一个ImageView上,在多线程操作时,Android中必须保证 ...