Android之基于xmpp openfire smack开发之smack类库介绍和使用[2]

http://blog.csdn.net/shimiso/article/details/8816540

关于Smack编程库,前面我们提到,它是面向Java端的api,主要在PC上使用,利用它我们可以向openfire服务器注册用户,发送消息,并且可以通过监听器获得此用户的应答消息,以及构建聊天室,分组,个人通讯录等等。


下面我们写几个程序小例子测试一下。

(1)登录操作

PPConnection.DEBUG_ENABLED = true;  
AccountManager accountManager;  
final ConnectionConfiguration connectionConfig = new ConnectionConfiguration(  "192.168.1.78", Integer.parseInt("5222"), "csdn.shimiso.com");  // 允许自动连接  
connectionConfig.setReconnectionAllowed(true);  
connectionConfig.setSendPresence(true);  Connection connection = new XMPPConnection(connectionConfig);  
try {  connection.connect();// 开启连接  accountManager = connection.getAccountManager();// 获取账户管理类  
} catch (XMPPException e) {  throw new IllegalStateException(e);  
}  // 登录  
connection.login("admin", "admin","SmackTest");  
System.out.println(connection.getUser());   
connection.getChatManager().createChat("shimiso@csdn.shimiso.com",null).sendMessage("Hello word!");  
运行结果:

在login中一共有三个参数,登录名,密码,资源名,可能有人不明白资源名到底是什么意思,其实就是客户端的来源,客户端的名称,如果不写它默认就叫smack,如果你用相同的账户不同的资源名和同一个人发三条消息,那将会弹出三个窗口,而不是一个窗口。
同时smack还为我们提供了非常好的调试工具Smack Debug,利用该工具我们可以准确的捕获详细的往返报文信息。

(2)下面我们继续写个聊天的例子:

PPConnection.DEBUG_ENABLED = true;  
AccountManager accountManager;  
final ConnectionConfiguration connectionConfig = new ConnectionConfiguration(  "192.168.1.78", Integer.parseInt("5222"), "csdn.shimiso.com");  // 允许自动连接  
connectionConfig.setReconnectionAllowed(true);  
connectionConfig.setSendPresence(true);  Connection connection = new XMPPConnection(connectionConfig);  
try {  connection.connect();// 开启连接  accountManager = connection.getAccountManager();// 获取账户管理类  
} catch (XMPPException e) {  throw new IllegalStateException(e);  
}  // 登录  
connection.login("admin", "admin","SmackTest3");    
ChatManager chatmanager = connection.getChatManager();  
Chat newChat = chatmanager.createChat("shimiso@csdn.shimiso.com", new MessageListener() {  public void processMessage(Chat chat, Message message) {  if (message.getBody() != null) {  System.out.println("Received from 【"  + message.getFrom() + "】 message: "  + message.getBody());  }  }  
});  
Scanner input = new Scanner(System.in);  
while (true) {  String message = input.nextLine();   newChat.sendMessage(message);  
}  
运行结果:

这里我们用Scanner来捕捉用户在控制台的键盘操作,将信息发出,同时创建了一个MessageListener监听,在其中强制实现processMessage方法即可捕获发回的信息,在初次使用上还是较为容易上手的,我们只要细心查看API即可逐步深入下去。

(3)除了聊天以外我们经常还能想到就是广播

需要给所有在线的用户发送一个通知,或者给所有在线和离线的用户全发送,我们先演示如何给在线用户发送一个广播:

PPConnection.DEBUG_ENABLED = false;  
AccountManager accountManager;  
final ConnectionConfiguration connectionConfig = new ConnectionConfiguration(  "192.168.1.78", Integer.parseInt("5222"), "csdn.shimiso.com");  // 允许自动连接  
connectionConfig.setReconnectionAllowed(true);  
connectionConfig.setSendPresence(true);  Connection connection = new XMPPConnection(connectionConfig);  
try {  connection.connect();// 开启连接  accountManager = connection.getAccountManager();// 获取账户管理类  
} catch (XMPPException e) {  throw new IllegalStateException(e);  
}  
connection.login("admin", "admin","SmackTest3");   
Message newmsg = new Message();   
newmsg.setTo("shimiso@csdn.shimiso.com");  
newmsg.setSubject("重要通知");  
newmsg.setBody("今天下午2点60分有会!");  
newmsg.setType(Message.Type.headline);// normal支持离线   
connection.sendPacket(newmsg);  
connection.disconnect();  
运行结果:

将参数设置为Message.Type.normal即可支持离线广播,openfire系统会自动判断该用户是否在线,如果在线就直接发送出去,如果不在线则将信息存入ofoffline表,现在我将shimiso用户退出登录,再给它发消息,我们可以进入openfire库的ofoffline表中,非常清楚看到里面躺着一条离线消息记录是发给shimiso这个用户的


(4)那么我们如何让shimiso这个用户一登陆就取到离线消息呢?

请看如下代码

PPConnection.DEBUG_ENABLED = false;  
AccountManager accountManager;  
final ConnectionConfiguration connectionConfig = new ConnectionConfiguration(  "192.168.1.78", Integer.parseInt("5222"), "csdn.shimiso.com");  // 允许自动连接  
connectionConfig.setReconnectionAllowed(true);  
connectionConfig.setSendPresence(false);//不要告诉服务器自己的状态  
Connection connection = new XMPPConnection(connectionConfig);  
try {  connection.connect();// 开启连接  accountManager = connection.getAccountManager();// 获取账户管理类  
} catch (XMPPException e) {  throw new IllegalStateException(e);  
}   
connection.login("shimiso", "123","SmackTest");   
OfflineMessageManager offlineManager = new OfflineMessageManager(  connection);  
try {  Iterator<org.jivesoftware.smack.packet.Message> it = offlineManager  .getMessages();  System.out.println(offlineManager.supportsFlexibleRetrieval());  System.out.println("离线消息数量: " + offlineManager.getMessageCount());  Map<String, ArrayList<Message>> offlineMsgs = new HashMap<String, ArrayList<Message>>();  while (it.hasNext()) {  org.jivesoftware.smack.packet.Message message = it.next();  System.out  .println("收到离线消息, Received from 【" + message.getFrom()  + "】 message: " + message.getBody());  String fromUser = message.getFrom().split("/")[0];  if (offlineMsgs.containsKey(fromUser)) {  offlineMsgs.get(fromUser).add(message);  } else {  ArrayList<Message> temp = new ArrayList<Message>();  temp.add(message);  offlineMsgs.put(fromUser, temp);  }  }  // 在这里进行处理离线消息集合......  Set<String> keys = offlineMsgs.keySet();  Iterator<String> offIt = keys.iterator();  while (offIt.hasNext()) {  String key = offIt.next();  ArrayList<Message> ms = offlineMsgs.get(key);  for (int i = 0; i < ms.size(); i++) {  System.out.println("-->" + ms.get(i));  }  }  offlineManager.deleteMessages();  
} catch (Exception e) {  e.printStackTrace();  
}  
offlineManager.deleteMessages();//删除所有离线消息  
Presence presence = new Presence(Presence.Type.available);  nnection.sendPacket(presence);//上线了  nnection.disconnect();//关闭连接  
运行结果:


这里我们需要特别当心的是先不要告诉openfire服务器你上线了,否则永远也拿不到离线消息,用下面英文大概意思就是在你上线之前去获取离线消息,这么设计是很有道理的。

The OfflineMessageManager helps manage offline messages even before the user has sent an available presence. When a user asks for his offline messages before sending an available presence then the server will not send a flood with all the offline messages when the user becomes online. The server will not send a flood with all the offline messages to the session that made the offline messages request or to any other session used by the user that becomes online.

拿到离线消息处理完毕之后删除离线消息offlineManager.deleteMessages() 接着通知服务器上线了。

(5)下面我们来看看如何来发送文件

PPConnection.DEBUG_ENABLED = false;  
AccountManager accountManager;  
final ConnectionConfiguration connectionConfig = new ConnectionConfiguration(  "192.168.1.78", Integer.parseInt("5222"), "csdn.shimiso.com");  // 允许自动连接  
connectionConfig.setReconnectionAllowed(true);  
connectionConfig.setSendPresence(true);  Connection connection = new XMPPConnection(connectionConfig);  
try {  connection.connect();// 开启连接  accountManager = connection.getAccountManager();// 获取账户管理类  
} catch (XMPPException e) {  throw new IllegalStateException(e);  
}  connection.login("admin", "admin","Rooyee");   Presence pre = connection.getRoster().getPresence("shimiso@csdn.shimiso.com");  System.out.println(pre);  if (pre.getType() != Presence.Type.unavailable) {  // 创建文件传输管理器  FileTransferManager manager = new FileTransferManager(connection);  // 创建输出的文件传输  OutgoingFileTransfer transfer = manager  .createOutgoingFileTransfer(pre.getFrom());  // 发送文件  transfer.sendFile(new File("E:\\Chrysanthemum.jpg"), "图片");  while (!transfer.isDone()) {  if (transfer.getStatus() == FileTransfer.Status.in_progress) {  // 可以调用transfer.getProgress();获得传输的进度   System.out.println(transfer.getStatus());  System.out.println(transfer.getProgress());  System.out.println(transfer.isDone());  }  }  }  
运行结果:

在这里我们需要特别注意的是,跨资源是无法发送文件的,看connection.login("admin", "admin","Rooyee");这个代码就明白了,必须是“域名和资源名”完全相同的两个用户才可以互发文件,否则永远都没反应,如果不清楚自己所用的客户端的资源名,可以借助前面提到的SmackDebug工具查看往返信息完整报文,在to和from中一定可以看到。

如果我们自己要写文件接收例子的话,参考代码如下:

FileTransferManager transfer = new FileTransferManager(connection);  
transfer.addFileTransferListener(new RecFileTransferListener());  
public class RecFileTransferListener implements FileTransferListener {  public String getFileType(String fileFullName) {  if (fileFullName.contains(".")) {  return "." + fileFullName.split("//.")[1];  } else {  return fileFullName;  }  }  @Override  public void fileTransferRequest(FileTransferRequest request) {  System.out.println("接收文件开始.....");  final IncomingFileTransfer inTransfer = request.accept();  final String fileName = request.getFileName();  long length = request.getFileSize();  final String fromUser = request.getRequestor().split("/")[0];  System.out.println("文件大小:" + length + "  " + request.getRequestor());  System.out.println("" + request.getMimeType());  try {  JFileChooser chooser = new JFileChooser();  chooser.setCurrentDirectory(new File("."));  int result = chooser.showOpenDialog(null);  if (result == JFileChooser.APPROVE_OPTION) {  final File file = chooser.getSelectedFile();  System.out.println(file.getAbsolutePath());  new Thread() {  public void run() {  try {  System.out.println("接受文件: " + fileName);  inTransfer  .recieveFile(new File(file  .getAbsolutePath()  + getFileType(fileName)));  Message message = new Message();  message.setFrom(fromUser);  message.setProperty("REC_SIGN", "SUCCESS");  message.setBody("[" + fromUser + "]发送文件: "  + fileName + "/r/n" + "存储位置: "  + file.getAbsolutePath()  + getFileType(fileName));  if (Client.isChatExist(fromUser)) {  Client.getChatRoom(fromUser)  .messageReceiveHandler(message);  } else {  ChatFrameThread cft = new ChatFrameThread(  fromUser, message);  cft.start();  }  } catch (Exception e2) {  e2.printStackTrace();  }  }  }.start();  } else {  System.out.println("拒绝接受文件: " + fileName);  request.reject();  Message message = new Message();  message.setFrom(fromUser);  message.setBody("拒绝" + fromUser + "发送文件: " + fileName);  message.setProperty("REC_SIGN", "REJECT");  if (Client.isChatExist(fromUser)) {  Client.getChatRoom(fromUser).messageReceiveHandler(message);  } else {  ChatFrameThread cft = new ChatFrameThread(fromUser, message);  cft.start();  }  }  /* * InputStream in = inTransfer.recieveFile(); *  * String fileName = "r"+inTransfer.getFileName(); *  * OutputStream out = new FileOutputStream(new * File("d:/receive/"+fileName)); byte[] b = new byte[512]; * while(in.read(b) != -1) { out.write(b); out.flush(); } *  * in.close(); out.close(); */  } catch (Exception e) {  e.printStackTrace();  }  System.out.println("接收文件结束.....");  }  }  

(6)用户列表

**  * 返回所有组信息 <RosterGroup>  *   * @return List(RosterGroup)  */  
public static List<RosterGroup> getGroups(Roster roster) {  List<RosterGroup> groupsList = new ArrayList<RosterGroup>();  Collection<RosterGroup> rosterGroup = roster.getGroups();  Iterator<RosterGroup> i = rosterGroup.iterator();  while (i.hasNext())  groupsList.add(i.next());  return groupsList;  
}  /** * 返回相应(groupName)组里的所有用户<RosterEntry> *  * @return List(RosterEntry) */  
public static List<RosterEntry> getEntriesByGroup(Roster roster,  String groupName) {  List<RosterEntry> EntriesList = new ArrayList<RosterEntry>();  RosterGroup rosterGroup = roster.getGroup(groupName);  Collection<RosterEntry> rosterEntry = rosterGroup.getEntries();  Iterator<RosterEntry> i = rosterEntry.iterator();  while (i.hasNext())  EntriesList.add(i.next());  return EntriesList;  
}  /** * 返回所有用户信息 <RosterEntry> *  * @return List(RosterEntry) */  
public static List<RosterEntry> getAllEntries(Roster roster) {  List<RosterEntry> EntriesList = new ArrayList<RosterEntry>();  Collection<RosterEntry> rosterEntry = roster.getEntries();  Iterator<RosterEntry> i = rosterEntry.iterator();  while (i.hasNext())  EntriesList.add(i.next());  return EntriesList;  
}  

(7)用户头像的获取

使用VCard,很强大,具体自己看API吧,可以看看VCard传回来XML的组成,含有很多信息的

**  * 获取用户的vcard信息  * @param connection  * @param user  * @return  * @throws XMPPException  */  
public static VCard getUserVCard(XMPPConnection connection, String user) throws XMPPException  
{  VCard vcard = new VCard();  vcard.load(connection, user);  return vcard;  
}  /** * 获取用户头像信息 */  
public static ImageIcon getUserImage(XMPPConnection connection, String user) {  ImageIcon ic = null;  try {  System.out.println("获取用户头像信息: "+user);  VCard vcard = new VCard();  vcard.load(connection, user);  if(vcard == null || vcard.getAvatar() == null)  {  return null;  }  ByteArrayInputStream bais = new ByteArrayInputStream(  vcard.getAvatar());  Image image = ImageIO.read(bais);  ic = new ImageIcon(image);  System.out.println("图片大小:"+ic.getIconHeight()+" "+ic.getIconWidth());  } catch (Exception e) {  e.printStackTrace();  }  return ic;  
}  

(8)组操作和用户分组操作

**  * 添加一个组  */  
public static boolean addGroup(Roster roster,String groupName)  
{  try {  roster.createGroup(groupName);  return true;  } catch (Exception e) {  e.printStackTrace();  return false;  }  
}  /** * 删除一个组 */  
public static boolean removeGroup(Roster roster,String groupName)  
{  return false;  
}  /** * 添加一个好友  无分组 */  
public static boolean addUser(Roster roster,String userName,String name)  
{  try {  roster.createEntry(userName, name, null);  return true;  } catch (Exception e) {  e.printStackTrace();  return false;  }  
}  
/** * 添加一个好友到分组 * @param roster * @param userName * @param name * @return */  
public static boolean addUser(Roster roster,String userName,String name,String groupName)  
{  try {  roster.createEntry(userName, name,new String[]{ groupName});  return true;  } catch (Exception e) {  e.printStackTrace();  return false;  }  
}  /** * 删除一个好友 * @param roster * @param userName * @return */  
public static boolean removeUser(Roster roster,String userName)  
{  try {  if(userName.contains("@"))  {  userName = userName.split("@")[0];  }  RosterEntry entry = roster.getEntry(userName);  System.out.println("删除好友:"+userName);  System.out.println("User: "+(roster.getEntry(userName) == null));  roster.removeEntry(entry);  return true;  } catch (Exception e) {  e.printStackTrace();  return false;  }  }  

(9)用户查询

public static List<UserBean> searchUsers(XMPPConnection connection,String serverDomain,String userName) throws XMPPException  {  List<UserBean> results = new ArrayList<UserBean>();  System.out.println("查询开始..............."+connection.getHost()+connection.getServiceName());  UserSearchManager usm = new UserSearchManager(connection);  Form searchForm = usm.getSearchForm(serverDomain);  Form answerForm = searchForm.createAnswerForm();  answerForm.setAnswer("Username", true);  answerForm.setAnswer("search", userName);  ReportedData data = usm.getSearchResults(answerForm, serverDomain);  Iterator<Row> it = data.getRows();  Row row = null;  UserBean user = null;  while(it.hasNext())  {  user = new UserBean();  row = it.next();  user.setUserName(row.getValues("Username").next().toString());  user.setName(row.getValues("Name").next().toString());  user.setEmail(row.getValues("Email").next().toString());  System.out.println(row.getValues("Username").next());  System.out.println(row.getValues("Name").next());  System.out.println(row.getValues("Email").next());  results.add(user);  //若存在,则有返回,UserName一定非空,其他两个若是有设,一定非空  }  return results;  }  

(10)修改自身状态

包括上线,隐身,对某人隐身,对某人上线

ublic static void updateStateToAvailable(XMPPConnection connection)  
{  Presence presence = new Presence(Presence.Type.available);  nnection.sendPacket(presence);  public static void updateStateToUnAvailable(XMPPConnection connection)  
{  Presence presence = new Presence(Presence.Type.unavailable);  nnection.sendPacket(presence);  }  public static void updateStateToUnAvailableToSomeone(XMPPConnection connection,String userName)  
{  Presence presence = new Presence(Presence.Type.unavailable);  presence.setTo(userName);  nnection.sendPacket(presence);  
}  
public static void updateStateToAvailableToSomeone(XMPPConnection connection,String userName)  
{  Presence presence = new Presence(Presence.Type.available);  presence.setTo(userName);  nnection.sendPacket(presence);  }  

(11)心情修改

**  * 修改心情  * @param connection  * @param status  */  
public static void changeStateMessage(XMPPConnection connection,String status)  
{  Presence presence = new Presence(Presence.Type.available);  presence.setStatus(status);  connection.sendPacket(presence);  }  

(12)修改用户头像

有点麻烦,主要是读入图片文件,编码,传输之

public static void changeImage(XMPPConnection connection,File f) throws XMPPException, IOException{  VCard vcard = new VCard();  vcard.load(connection);  byte[] bytes;  bytes = getFileBytes(f);  String encodedImage = StringUtils.encodeBase64(bytes);  vcard.setAvatar(bytes, encodedImage);  vcard.setEncodedImage(encodedImage);  vcard.setField("PHOTO", "<TYPE>image/jpg</TYPE><BINVAL>"  + encodedImage + "</BINVAL>", true);  ByteArrayInputStream bais = new ByteArrayInputStream(  vcard.getAvatar());  Image image = ImageIO.read(bais);  ImageIcon ic = new ImageIcon(image);  vcard.save(connection);  }  private static byte[] getFileBytes(File file) throws IOException {  BufferedInputStream bis = null;  try {  bis = new BufferedInputStream(new FileInputStream(file));  int bytes = (int) file.length();  byte[] buffer = new byte[bytes];  int readBytes = bis.read(buffer);  if (readBytes != buffer.length) {  throw new IOException("Entire file not read");  }  return buffer;  } finally {  if (bis != null) {  bis.close();  }  }  
}  

(13)用户状态的监听

即对方改变头像,状态,心情时,更新自己用户列表,其实这里已经有smack实现的监听器

nal Roster roster = Client.getRoster();  roster.addRosterListener(  new RosterListener() {  @Override  public void entriesAdded(Collection<String> arg0) {  // TODO Auto-generated method stub  System.out.println("--------EE:"+"entriesAdded");  }  @Override  public void entriesDeleted(Collection<String> arg0) {  // TODO Auto-generated method stub  System.out.println("--------EE:"+"entriesDeleted");  }  @Override  public void entriesUpdated(Collection<String> arg0) {  // TODO Auto-generated method stub  System.out.println("--------EE:"+"entriesUpdated");  }  @Override  public void presenceChanged(Presence arg0) {  // TODO Auto-generated method stub  System.out.println("--------EE:"+"presenceChanged");  }     });  
下载:项目















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

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

相关文章

python 线程 的类库_python类库32[多线程]

一 python 多线程因为CPython的实现使用了Global Interpereter Lock(GIL)&#xff0c;使得python中同一时刻只有一个线程在执行&#xff0c;从而简化了python解释器的实现&#xff0c;且python对象模型天然地线程安全。如果你想你的应用程序在多核的机器上使用更好的资源&#…

当.NET遇到机器学习

微软中国MSDN 点击上方蓝字关注我们ML.NET 是面向 .NET 开发人员的开源跨平台机器学习框架&#xff0c;你可以使用 C# 或 F# 创建自定义 ML 模型&#xff0c;而无需离开.NET 生态系统。ML.NET 使你能够在联机或脱机场景中将机器学习添加到 .NET 应用程序中。借助此功能&#x…

当你和你女朋友闹矛盾时......

1 听起来是这么个道理&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼2 真的是非常专一了&#xff08;via.皎皎月当楼&#xff09;▼3 给朋友定做的蛋糕&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼4 当你和女朋友闹矛盾时▼5 师范的男孩子有多害怕&a…

Android之基于xmpp openfire smack开发之Android客户端开发[3]

http://blog.csdn.net/shimiso/article/details/11225873 在上两篇文章中&#xff0c;我们依次介绍openfire部署以及smack常用API的使用&#xff0c;这一节中我们着力介绍如何基于asmack开发一个Android的客户端&#xff0c;本篇的重点在实践&#xff0c;讲解和原理环节&#…

PowerToys插件扩展(类似Alfred)

在mac系统除了自带的Spotlight还有一个很好用的工具叫Alfredimage在windows系统也有一个很好用的工具叫PowerToys&#xff0c;是微软的一个开源项目imagehttps://github.com/microsoft/PowerToys从上面的github地址可以下载安装包。image它有很多快捷功能&#xff0c;请大家自己…

Android之基于xmpp openfire smack开发之Android消息推送技术原理分析和实践[4]

http://blog.csdn.net/shimiso/article/details/8156439 前面几篇给大家系统讲解的有关xmpp openfire smack asmack相关的技术和使用&#xff0c;大家如果有所遗忘可以参考 顺便也一起回顾下xmpp的历程 xmpp协议起源于著名的Linux即时通讯服务服务器jabber,有时候我们会把xmp…

12年前的高考到底有多难,只在这一道题上就看出来了...

▲ 点击查看2008年高考江西数学考卷的最后一题&#xff0c;说是高考史上最恐怖的数学题&#xff0c;应该没有异议。这道题到底有多难呢&#xff1f;最后这道压轴题一共是14分。考试结果出来&#xff0c;所有考生的平均分是0.31分。曾有一位同学这样介绍&#xff1a;“在我们学校…

Cypher查询语言--Neo4j-WHERE(三)

目录 WhereBoolean 操作类型节点属性上的过滤正则表达式转义正则表达式不分大小些正则表达式关系类型上的过滤属性存在性如果缺失属性默认为true如果缺失属性默认为false空置null过滤关系过滤Where 如果需要从查找的数据的图中过滤&#xff0c;可以在查询语句中添加where子句。…

12篇学通C#网络编程——第一篇 基础之进程线程

在C#的网络编程中&#xff0c;进程和线程是必备的基础知识&#xff0c;同时也是一个重点&#xff0c;所以我们要好好的掌握一下。 一&#xff1a;概念 首先我们要知道什么是”进程”&#xff0c;什么是“线程”&#xff0c;好&#xff0c;查一下baike。 进程&#xff1a;是一个…

建立学生选课表 mysql 语句_MySQL常用SQL语句(Python实现学生、课程、选课表增删改查)...

以基本的学生选课为例&#xff0c;建立选课数据库&#xff0c;学生、班级、选课信息三张表&#xff0c;并分别对表进行插删改操作&#xff1a;import MySQLdbtry:conn MySQLdb.connect(host localhost, user root, passwd root, db xuanke, port 3306)cur conn.cursor()…

加快网站访问速度--jquery.js

jquery现在是越来越大&#xff0c;网络加载速度上我们应该做到能省就省&#xff0c;毫无疑问google的服务器和cdn以及访问速度是非常快的&#xff0c;而且google敞开怀抱&#xff0c;提供各种代码库给我们下载调用。jquery就是其中一个。 在jquery官网有从google 微软microsoft…

也谈程序员的35岁危机

前言本来这期要推一篇观察者模式和发布订阅模式的技术文给各位看官(在写了)&#xff0c;但无奈最近爱奇艺裁员事件引起了轩然大波&#xff0c;互联网上和各种技术群又展开了轰轰烈烈的讨论&#xff0c;每位IT从业者都不能独善其身。那么今天这一期我们就聊聊程序员的35岁危机究…

豆瓣评分9.4!这部大片你不应该错过,每一秒都是不敢看的残忍!

全世界只有3.14 % 的人关注了爆炸吧知识人类占据了地球上绝大多数宜居的地方&#xff0c;我们面对着温柔的地球母亲&#xff0c;但对野生动物们来说&#xff0c;地球却是一个水深火热的星球。你觉得你已经一无所有了&#xff0c;你觉得生活的负荷已经让你难以前进了&#xff1b…

Unity3D4.* NGUI制作动态字库

新建一个工程&#xff0c;这个工程必须没有中文路径&#xff0c;否则会不识别字体&#xff01;&#xff01;&#xff01; 首先导入NGUI插件&#xff0c;这里我用的是NGUI 3.0.2版本的。 在Assets 下创建一个文件夹&#xff0c;用来存放接下来的工作文件 。 这里随便选择一种字体…

java解析json_JAVA解析JSON数据

在使用第三方api的使用&#xff0c;有时候会从网络中获得json数据&#xff0c;所以说我们将如何解析json数据&#xff1f;下面小编将通过以下几点来进行json的讲解JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read…

Android之android studio如何解决‘:app:packageDebug‘.(Duplicate files copied in APK META-INF/DEPENDENCIES)

不废话&#xff0c;先爆照 今天在使用glide的时候&#xff0c;我在项目里面添加了httpcore-4.3.2.jar和4.3.5.jar包&#xff0c;但是当我运行的时候就出现了这个错误 然后在build.gradle里面配置下面的信息就好了&#xff0c; android { packagingOptions { exclude META-IN…

Asp.Net MVC4.0 官方教程 入门指南之一-- 入门介绍

本教程将为您讲解使用微软的Visual Studio 2012 来建立一个ASP.NET MVC4 Web应用程序所需要的基础知识。 本示例将构建什么样的应用程序&#xff1f; 您将实现一个简单的电影管理应用程序&#xff0c;此程序将从数据库中选取记录展示列表&#xff0c;支持查询和查看&#xff0…

关注!这所211高校通知不放寒假!校园将实行封闭管理!

全世界只有3.14 % 的人关注了爆炸吧知识本文转自&#xff1a;募格学术新年伊始&#xff0c;北京顺义&#xff0c;辽宁大连、沈阳&#xff0c;黑龙江黑河&#xff0c;河北石家庄、邢台等地相继报告新增本土病例&#xff0c;随着春节的临近&#xff0c;人员流动和聚集增加&#x…

MediatR 在.NET应用中的实践

MediatR 简介MediatR是.NET中的开源简单中介者模式实现.它通过一种进程内消息传递机制&#xff08;无其他外部依赖&#xff09;&#xff0c;进行请求/响应、命令、查询、通知和事件的消息传递&#xff0c;并通过泛型来支持消息的智能调度。开源库地址是https://github.com/jbog…

java 录屏_java 录屏 小工具源码(idea)

【实例简介】录制的视频保存在 java.io.tmpdir 目录&#xff0c;windows通常为 C:\Users\Administrator\AppData\Local\Temp【实例截图】点击播放后&#xff0c;效果如下&#xff1a;【核心代码】import java.awt.AWTException;import java.awt.Color;import java.awt.Dimensio…