索引

  • 1.开发契机
  • 2.软件概述
  • 3.服务器端
  • 4.客户端
    • 4.1 登录界面:MainActivity
    • 4.2 聊天界面:ChatRoom
  • 5.特点

1.开发契机

很早之前就想自己做出一个仅实现远程聊天功能,而不带有任何冗余功能的超级轻量化聊天软件。参考了众多开源的聊天软件源代码,发现大部分是使用socket实现了私有网络的通信。当时也是苦恼了一段时间,最终使用了JSON格式对聊天记录进行存储,并通过HTTP协议对JSON数据进行传输,从而实现了这个轻量化的聊天软件。

2.软件概述

该聊天软件不涉及数据库,所有聊天记录以JSON的形式存储于服务器的内存中。用户通过在登录界面登录以后便进入了一个公共的聊天室,可以通过公共网络与任何一个同样使用这个应用的用户进行聊天。以下分别是登录界面和聊天界面。

使用的开发工具及环境:
①Eclipse Java EE IDE for Web Developers. Version: Mars.1 Release (4.5.1)
②Android Studio 3.5.3

3.服务器端

我在本机搭建了Tomcat服务器作为Web应用的容器,使用Servlet来实现聊天的业务逻辑。
由于使用到了JSON数据,所以需要在相应的Web应用项目中的 WEB-INF\lib 文件夹下导入6个jar包定义了一个DiffServlet

package com.chatroom;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
@WebServlet("/DiffServlet")
public class DiffServlet extends HttpServlet {private static final long serialVersionUID = 1L;private static JSONArray messageList = new JSONArray();public DiffServlet() {super();// TODO Auto-generated constructor stub}public void init()throws ServletException{   //初始化,创建一个JSON对象列表,if(messageList.isEmpty()) {          //用于存储聊天记录JSONObject first = new JSONObject();first.put("name", "Server");first.put("message", "Server Gets Ready");messageList.add(first);}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 对http请求的Get方法进行响应,为客户端返回所有聊天记录request.setCharacterEncoding("UTF-8");response.setContentType("application/json;charset=UTF-8");PrintWriter out = response.getWriter();out.write(messageList.toString());out.flush();out.close();}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 对http请求的Post方法进行响应,将客户端发来的信息添加到聊天记录列表当中request.setCharacterEncoding("UTF-8");response.setContentType("application/json;charset=UTF-8");String username = request.getParameter("name");String message = request.getParameter("message");JSONObject obj = new JSONObject();obj.put("name", username);obj.put("message", message);messageList.add(obj);}
}

在web.xml对该Servlet进行注册

  <servlet><servlet-name>DiffServlet</servlet-name><servlet-class>com.ChatRoom.DiffServlet</servlet-class></servlet><servlet-mapping><servlet-name>DiffServlet</servlet-name><url-pattern>/ChatRoom/DiffServlet</url-pattern></servlet-mapping>

4.客户端

Android客户端包含两个Activity,一个是登录界面MainActivity,一个是聊天界面ChatRoom。所有的活动要在AndroidManifest.xml文件中进行注册,为了使用户在应用中使用输入法使界面的背景图不会被压缩,所以在每个活动标签中加入

android:windowSoftInputMode="adjustPan"

这样一条代码,就可以解决背景图片被压缩的问题了。
由于项目中要使用网络,所以要在AndroidManifest.xml文件中对授权对网络的访问,添加如下代码:

<uses-permission android:name="android.permission.INTERNET"/>

注意
如果我们使用的是http协议的域名,使用Android Studio开发的应用可能会与主机连接不上,出现这种情况可参考6号楼下的大懒喵的博客 OkHttp请求http链接失败的问题

4.1 登录界面:MainActivity

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/picture"><EditTextandroid:id="@+id/et_name"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center"android:gravity="center"android:hint="用户名"/><Buttonandroid:id="@+id/btn_cnt"android:layout_width="100dp"android:layout_height="wrap_content"android:background="#07D0F3"android:gravity="center"android:layout_gravity="center"android:text="连接"android:textColor="#ffffff" />
</LinearLayout>

源代码:

package com.example.chatroom;import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;public class MainActivity extends AppCompatActivity implements View.OnClickListener {private Button btn_cnt;private EditText et_name;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btn_cnt = (Button) findViewById(R.id.btn_cnt);et_name = findViewById(R.id.et_name);btn_cnt.setOnClickListener(MainActivity.this);}public void onClick(View view) {String name = et_name.getText().toString();if ("".equals(name)) {Toast.makeText(this, "请输入用户名:", Toast.LENGTH_SHORT).show();//如果输入的用户名为空的话,那么下端会出现提示} else {Intent intent=new Intent(MainActivity.this,ChatRoom.class);intent.putExtra("username",name);startActivity(intent);}}
}

4.2 聊天界面:ChatRoom

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:orientation="vertical"android:background="#d8e0e8"android:layout_width="match_parent"android:layout_height="match_parent"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/msg_recycler_view"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:background="@drawable/background" /><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"><EditTextandroid:id="@+id/input_text"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:background="#ffffff"/><Buttonandroid:id="@+id/send"android:layout_width="wrap_content"android:layout_height="50dp"android:background="#07D0F3"android:text="发送"android:textColor="#ffffff" /></LinearLayout>
</LinearLayout>

源代码:

package com.example.chatroom;import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import org.json.JSONArray;
import org.json.JSONObject;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class ChatRoom extends AppCompatActivity implements View.OnClickListener{private List<Msg> msgList = new ArrayList<>();private EditText inputText;private Button send;private RecyclerView msgRecyclerView;private MsgAdapter adapter;boolean isRunning = false;private boolean isSend=false;private String myName;private String responseData;private int curr;                   //当前显示的消息条数private int jsonLen;                //获取到的json列表长度private Handler handler = new Handler(Looper.myLooper()){//获取当前进程的Looper对象传给handler//在目前的Android开发中,子线程不能改变UI,//所以子线程要对UI进行操作需要交给一个Handler对象来执行@Overridepublic void handleMessage(Message message){String message_Name = message.getData().getString("name");String message_msgC = message.getData().getString("msgContent");if(!message_msgC.equals("")){if(message_Name.equals(myName))addNewMessage(message_msgC, Msg.TYPE_SENT);elseaddNewMessage(message_msgC,Msg.TYPE_RECEIVED);}}};public void addNewMessage(String msg,int type){Msg message = new Msg(msg,type);msgList.add(message);adapter.notifyItemInserted(msgList.size()-1);msgRecyclerView.scrollToPosition(msgList.size()-1);}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_chat_room);Intent intent =getIntent();myName=intent.getStringExtra("username");curr=0;jsonLen=1;isRunning=true;inputText = findViewById(R.id.input_text);send=findViewById(R.id.send);send.setOnClickListener(this);runOnUiThread(new Runnable() {@Overridepublic void run() {LinearLayoutManager layoutManager = new    LinearLayoutManager(ChatRoom.this);msgRecyclerView= findViewById(R.id.msg_recycler_view);msgRecyclerView.setLayoutManager(layoutManager);adapter = new MsgAdapter(msgList);msgRecyclerView.setAdapter(adapter);}});new Thread(new Receive(), "接收线程").start(); new Thread(new Send(), "发送线程").start();}public void parseJSONWithJSONObject(String jsonData) {  //解析JSON数据函数try {JSONArray jsonArray = new JSONArray(jsonData);jsonLen = jsonArray.length();for (; curr < jsonLen; curr++) {JSONObject jsonObject = jsonArray.getJSONObject(curr);String name = jsonObject.getString("name");String msgContent = jsonObject.getString("message");Message message = new Message();Bundle bundle = new Bundle();bundle.putString("name", name);bundle.putString("msgContent", msgContent);  //往Bundle中存放数据message.setData(bundle);//mes利用Bundle传递数据handler.sendMessage(message);//用activity中的handler发送消息}} catch (Exception e) {Looper.prepare();Toast.makeText(ChatRoom.this, "解析json错误!", Toast.LENGTH_SHORT).show();Looper.loop();}
}String msgEntity;@Overridepublic void onClick(View view){String content = inputText.getText().toString();@SuppressLint("SimpleDateFormat")String date = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());StringBuilder sb = new StringBuilder();msgEntity = myName;sb.append(msgEntity).append("\n"+date+"\n"+content);msgEntity = sb.toString();if(!"".equals(msgEntity)){Message message = new Message();Bundle bundle = new Bundle();bundle.putString("name", myName);bundle.putString("msgContent", msgEntity);  //往Bundle中存放数据message.setData(bundle);//mes利用Bundle传递数据handler.sendMessage(message);//用activity中的handler发送消息inputText.setText("");isSend = true;curr++;}sb.delete(0,sb.length());}class Send implements Runnable{@Overridepublic void run(){           //发送线程while(isRunning){if(isSend){RequestBody requestBody = new FormBody.Builder().add("name",myName).add("message",msgEntity).build();try {OkHttpClient client = new OkHttpClient();Request request2 = new Request.Builder()// 指定访问的服务器地址.url(Resource.DiffUrl).post(requestBody).build();Response response = client.newCall(request2).execute();String responseData = response.body().string();isSend = false;} catch (Exception e) {Looper.prepare();Toast.makeText(ChatRoom.this, "发送失败!", Toast.LENGTH_SHORT).show();Looper.loop();}}}}}class Receive implements Runnable{public void run(){while(isRunning){if(!isSend) {try {OkHttpClient client = new OkHttpClient();Request request = new Request.Builder()// 指定访问的服务器地址.url(Resource.DiffUrl).get().build();//Resource.DiffUrl为DiffSevlet的URL地址//其需要根据你的服务端Servlet的URL地址进行修改Response response = client.newCall(request).execute();String responseData = response.body().string();if (responseData != null && responseData.startsWith("\ufeff")){responseData = responseData.substring(1);}parseJSONWithJSONObject(responseData);} catch (Exception e) {Looper.prepare();Toast.makeText(ChatRoom.this, "连接服务器失败!!!",Toast.LENGTH_SHORT).show();Looper.loop();}}}}}

需要在build.gradle中添加库依赖

implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.squareup.okhttp3:okhttp:4.5.0'
implementation 'com.squareup.okio:okio:2.5.0'

Msg实体类以及MsgAdapter类的相关代码参考衣侠客的博客 Android聊天室(客户端)

5.特点

①由于该软件是通过动态维护一个JSON对象列表来存储聊天记录,所以服务器端不静态存储任何用户信息,所有信息都是存储在服务器内存当中,一旦关闭服务器,所有当前的聊天记录都会消失
②聊天记录可以通过浏览器查看。通过浏览器使用URL对Servlet进行访问使用的是Get方法,该软件则调用了Web端的doGet()方法,获取了JSON数据形式的聊天记录。

项目下载:
CSDN链接
https://download.csdn.net/download/qq_43599564/12553464
Github
https://github.com/kengkengkeng41/ChatRoom

Android简易聊天室软件(HTTP实现)相关推荐

  1. 连夜撸了一个简易聊天室

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 分不清轮询.长轮询?不知道什么时候该用websocket还 ...

  2. 撸一个简易聊天室,不信你学不会实时消息推送(附源码)

    点击上方 好好学java ,选择 星标 公众号重磅资讯,干货,第一时间送达 今日推荐:推荐 19 个 github 超牛逼项目!个人原创100W +访问量博客:点击前往,查看更多 分不清轮询.长轮询? ...

  3. Socket编程实现简易聊天室

    1.Socket基础知识 Socket(套接字)用于描述IP地址和端口,是通信链的句柄,应用程序可以通过Socket向网络发出请求或者应答网络请求. Socket是支持TCP/IP协议的网络通信的基本 ...

  4. 超详细:实现过程-Linux 环境下的简易聊天室,采用CS模型,实现多客户端之间的稳定数据传输。--注册和登录(但之后会连续更新内容,直至全部实现)

    前言 在学完不够全面的Linux操作系统编程后(这也意味着我后期也要不断学习,这也符合我活到老学到老的人生观点),需要以一些项目来检测自己的所学,毕竟实践见真章. 所以在今后的几天里,我将以无界面聊天 ...

  5. html+css+js实现post简易聊天室

    目录 1.简述 2.效果图 3.核心代码讲解 A.把具体问题通过post请求上传到远程服务器 B.解析服务器返回的答复,并插入到聊天框 4.源码 1.简述 因为项目需求,就做了一个简易的聊天室,用户输 ...

  6. java聊天室程序_Java简易聊天室程序socket

    Java简易聊天室程序socket chatroomdemo.java package com.socket.demo; import java.io.IOException; import java ...

  7. Express+Socket.IO 实现简易聊天室

    代码地址如下: http://www.demodashi.com/demo/12477.html 闲暇之余研究了一下 Socket.io,搭建了一个简易版的聊天室,如有不对之处还望指正,先上效果图: ...

  8. 基于Node.js + WebSocket 的简易聊天室

    代码地址如下: http://www.demodashi.com/demo/13282.html Node.js聊天室运行说明 Node.js的本质就是运行在服务端的JavaScript.Node.j ...

  9. 视频聊天室软件的技术标准

    视频聊天室软件的技术标准 常规视频聊天软件的自定义功能及组别 可以根据自己运营的需要添加无限组别,并给不同的组别设定不同功能及图标: 自定义组别的权限,是否能踢人,是否能看密麦等: 视频聊天软件超低带 ...

  10. docker搭建swoole简易聊天室

    docker搭建swoole的简易聊天室 首先pull镜像 docker pull docker.io/kong36088/nginx-php7-swoole 创建容器 docker run --na ...

最新文章

  1. Windows server 2008 R2 通过策略关闭密码复杂性
  2. python大学课程-利用python完成大学刷课(从0到完成的思路)
  3. [云炬创业基础笔记]第九章企业的法律形态测试8
  4. 2018 计蒜之道 复赛
  5. Array.sort排序
  6. Python小白的数学建模课-18.最小生成树问题
  7. patch请求_SpringMVC源码学习(三) 请求处理的流程
  8. 简洁的 HTML5 音乐播放器
  9. interpeter用python还是pythonw_python-interpreter
  10. 四则运算界面版 结对子
  11. [转]McAfee 病毒库最新离线升级包下载 VirusScan SuperDAT
  12. 中职微型计算机说课,微型计算机原理说课.ppt
  13. libcef-案例展示-将cef浏览器嵌入到mfc中作为子窗口运行
  14. windows PE文件结构及其加载机制
  15. VM无法获取 vmci 驱动程序版本句柄无效解决办法
  16. android横向分割线,Android在两个分隔线之间水平对齐TextView
  17. 最近整理的Android学习笔记
  18. 代购源码,淘宝代购系统源码,代购程序,代购系统源码PHP前端源码参数说明
  19. 【复盘】如何写一份教程?
  20. 12星座之追女必杀技~

热门文章

  1. 经验正交函数分析(EOF)或主成分分析(PCA)在matlab上的实现及实例
  2. 粒子滤波(Particle filter)算法简介及MATLAB实现
  3. 组建局域网_组网方案图文教程,双路由器有线搭建网络,公司家庭组建局域网...
  4. AVR单片机(ATmega128)单片机运算乘除法大约所需时间
  5. 项目管理系统与项目管理信息系统与配置管理系统与变更控制系统的区别
  6. 计算机视觉之图像分割——Snake模型(1译文)
  7. Android开发之获取GPS位置案例源码详解
  8. 安装虚拟机提示未能启用服务器,win7系统共享虚拟机提示VMware Workstation Server共享服务不能启动的解决方法...
  9. java考勤表导出_考勤打卡机导出的excel考勤时间表如何生成实用的考勤表
  10. 计算机组成和体系结构-Flynn分类法