Web小案例-聊天室
一、简单介绍
1、 项目名:MyChat(Maven工程项目)
2、开发环境:Win10
3、开发工具:Eclipse + Tomcat + Chrome
4、使用技术:HTML + CSS + JS + JSP + JAVA + Servlet
5、第三方包:json-lib
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
6、源码下载链接:https://pan.baidu.com/s/1F6sO_HScwcUJT9JRaaLfAQ
二、页面展示
1、 登录页面
主要功能:输入昵称进入聊天室。昵称检测,要求不为空;不能与已登录的用户重复。如果为空或重复则在输入框中显示提示信息,不能用提示信息作为昵称,确定昵称后提示是否以此昵称进入。
2、 聊天室页面
主要功能:用户退出按钮、当前时间显示、用户列表显示、聊天信息显示、发送消息、文件上传(所有文件类型、图片支持预览)、文件列表显示、文件下载,其他功能可以到源码中查看。
3、点击文件列表中的下载按钮可以查看和下载文件
三、AJAX简单封装
在处理页面请求时,多处用到了ajax请求,因此在这里做一下简单封装,大家也可以根据自己需求封装出合适的好用的ajax请求。
/** 获得ajax对象 */
function getXhr() {
var xhr;
if (window.XMLHttpRequest) {
// 非IE浏览器
xhr = new XMLHttpRequest();
} else {
// IE浏览器
xhr = new ActiveXObject("Microsoft.XMLHttp");
}
return xhr;
}
/**
* ajax请求,用来传输文本字符串
* @param method 请求方式:get、post
* @param url 请求路径
* @param param 请求参数
* @param resultType 返回结果类型:text、json
* @param success 成功回调函数:function(result) {}
* @param error 错误回调函数:function() {}
*/
function _ajax(method, url, param, resultType, success, error) {
// 获取ajax对象
var xhr = getXhr();
// 打开连接,发送数据
if (method == "get") {
xhr.open("get", url+"?"+param, true);
xhr.send(null);
} else if (method == "post") {
xhr.open("post", url, true);
// 请求头,传输字符串
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
xhr.send(param);
}
// 回调函数
success = success || function() {};
error = error || function() {};
// 绑定事件
xhr.onreadystatechange = function () {
// 返回数据
var resultData;
if (xhr.readyState == 4 && xhr.status == 200) {
var text = xhr.responseText;
if (resultType == "text") {
resultData = text;
} else if (resultType == "json") {
resultData = JSON.parse(text);
}
//console.log(resultData);
if (resultData) {
success(resultData);
} else {
error();
}
}
};
}
/**
* ajax请求,用来上传文件
* @param method 请求方式:post
* @param url 请求路径
* @param param 请求参数:表单数据formData
* @param resultType 返回结果类型:text、json
* @param success 成功回调函数:function(result) {}
* @param error 错误回调函数:function() {}
*/
function _ajaxF(method, url, param, resultType, success, error) {
// 获取ajax对象
var xhr = getXhr();
// 打开连接,发送数据
xhr.open("post", url, true);
xhr.send(param);
// 回调函数
success = success || function() {};
error = error || function() {};
// 绑定事件
xhr.onreadystatechange = function () {
// 返回数据
var resultData;
if (xhr.readyState == 4 && xhr.status == 200) {
var text = xhr.responseText;
if (resultType == "text") {
resultData = text;
} else if (resultType == "json") {
resultData = JSON.parse(text);
}
//console.log(resultData);
if (resultData) {
success(resultData);
} else {
error();
}
}
};
}
这里需要区别一下参数的写法:
传输字符串:"paramName"=paramValue&"paramName1"=paramValue1...
,
上传文件:参数为form表单对象,具体操作详见四、文件上传并保存到Tomcat服务器。
使用方法按要求传入参数即可。
四、文件上传并保存到Tomcat服务器
1、配置form表单,必须添加属性enctype="multipart/form-data"
,如果不添加默认为enctype="application/x-www-form-urlencoded"
只能发送字符串,与上面封装的第一个ajax请求设置的请求头是一样的。action和method属性中的值可以不写,因为是用ajax发请求提交,如果是用表单直接提交则要写。需要提交的数据都要写name属性,为了能在服务器端进行区分除了文件数据外还有其他数据。我这里随文件提交的还有昵称,这个只是为了满足这里的需求,需要根据实际情况来定。
<!-- enctype="enctype="multipart/form-data" -->
<form id="uploadFileForm" action="uploadFile.file" method="post" enctype="multipart/form-data">
<!-- name="file",文件框必须写name属性 -->
选择文件:<input id="file" name="file" type="file"/>
<input id="user_name" name="${nickName }" type="text" value="${nickName }"/>
<input id="send_file" type="button" value="发送文件"/>
</form>
2、获取form表单对象
var formData = new FormData(_id("uploadFileForm"));
3、发送请求
_ajaxF("post", "uploadFile.file", formData, "json",
function(result) {
//console.log(result);
if(result.msg == "文件上传成功") {
uploadFileEnd(id);
confirm(result.msg);
} else {
uploadFileEnd(id);
alert(result.msg);
}
},
function() {
alert("文件上传失败!");
}
);
4、获取项目在服务器中的绝对路径
String realPath = getServletContext().getRealPath("/");
本人笔记本上获取的路径:D:\SoftwareInstallation\Tomcat8.0\wtpwebapps\MyChat\
5、处理上传的文件,这里贴出整个方法,看起来更完整,也有注释
/**
* 上传文件
* @param req
* @param res
* @throws IOException
*/
private void uploadFile(HttpServletRequest req, HttpServletResponse res) throws IOException {
FileOperationUtil.createSaveUploadFiles(realPath);
// 获输出取流
PrintWriter pw = res.getWriter();
// 创建流
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
// 文件原名
String fileName = "";
// 文件保存之后的名字
String fileSaveName = "";
// 文件保存路径
String savePath = "";
// 昵称
String nickName = "";
// 返回消息
String msg = "";
try {
if (ServletFileUpload.isMultipartContent(req)) {
// 转换为文件上传请求
ServletRequestContext src = new ServletRequestContext(req);
// 文件列表
List<FileItem> fileItems = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(src);
for (FileItem file : fileItems) {
//System.out.println("FileItems:" + file);
// 从打印的信息中可以看出如果是文件,isFormField值为false
if (!file.isFormField()) {
//System.out.println("file:" + file);
fileName = file.getName();
// 文件扩展名
String fileType = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
fileSaveName = System.currentTimeMillis() + fileType;
savePath = realPath + FileOperationUtil.SAVE_UPLOAD_FILE + fileSaveName;
// 获取文件输入流
InputStream is = file.getInputStream();
bis = new BufferedInputStream(is);
// 创建文件输出流保存文件
FileOutputStream fos = new FileOutputStream(savePath);
bos = new BufferedOutputStream(fos);
// 字节数组
byte[] buf = new byte[1024 * 10];
int n = bis.read(buf);
while(n != -1) {
bos.write(buf, 0, n);
n = bis.read(buf);
}
} else {
nickName = file.getFieldName();
}
}
// 保存上传信息
UploadFile uFile = new UploadFile(nickName, fileName, fileSaveName, savePath, DateFormatUtil.timeFormat());
uFiles.add(uFile);
// 返回信息
msg = "{msg:'文件上传成功'}";
pw.println(JSONObject.fromObject(msg).toString());
FileOperationUtil.saveUploadFile(realPath, uFiles);
}
} catch (FileUploadException e) {
msg = "{msg:'文件上传失败'}";
pw.println(JSONObject.fromObject(msg).toString());
} finally {
pw.close();
if (bis != null) {
bis.close();
}
if (bos != null) {
bos.close();
}
}
}
五、小结
以上代码是从案例中截取出来的,如果单看不好理解,可以下载源码结合源码一起看比较好。需要进一步了解的,想要玩一下的也可以下载源码。这个小案例中有些细节的地方没有处理好,欢迎大家一起交流。
智能推荐
Hadoop实战(4)_Hadoop的集群管理和资源分配
系列目录: Hadoop实战(1)_阿里云搭建Hadoop2.x的伪分布式环境 Hadoop实战(2)_虚拟机搭建Hadoop的全分布模式 Hadoop实战(3)_虚拟机搭建CDH的全分布模式 DataNode数据目录 如果有多个挂载点,可以有多个DataNode数据目录。 目前服务器硬件,标准小型机配置:32核、64G(128G)、64T(4T*16盘SAS盘)。通常为了提升磁盘吞吐量,每个盘单...
Tornado day02
一,项目模板: Tornado的项目也可以像Django和flask一样,将功能细分为几个模块 1.1 _ _ init _ _.py 1.2 setting .py 1.3 urls .py 1.4 views .py 1.5 manage .py 将这个模板拷贝下来,以后创建新项目的时候可以直接拷贝一份,在此模板上修改使用 文件链接 链接:https://pan.baidu.com/s/11E...
PAT乙级 | 1095 解码PAT准考证 (25分)(做题过程+注意事项+运行超时解决方法)
PAT 准考证号由 4 部分组成: 第 1 位是级别,即 T 代表顶级;A 代表甲级;B 代表乙级; 第 2~4 位是考场编号,范围从 101 到 999; 第 5~10 位是考试日期,格式为年、月、日顺次各占 2 位; 最后 11~13 位是考生编号,范围从 000 到 999。 现给定一系列考生的准考证号和他们的成绩,请你按照要求输出各种统计信息。 输入格式: 输入首先在一行中给出两个正整数 ...
谈谈Java异常
0 概述 对于java工程师来说,是经常和异常打交道的,本文主要来谈一谈java中的异常。 1 异常类的继承关系 从下图(说明:图中只是列出部分异常类)可以看出: 异常的基类为Throwable,主要分为两个分支,即Error体系和Exception体系。 Exception下面分为RuntimeException和非RuntimeException(如IOException) 2 几种异常的区别...
通过设立FatFS隐藏分区,实现系统文件和用户文件的隔离
嘛。。这是一个关于个人使用FatFS文件系统的 一点小的经验。 我知道大家都会百度和谷歌,关于文件系统有什么用,文件系统怎么移植上自己的平台,看看资料也就懂了,在这里不再详述( 打字太慢一分钟50-60字懒得写)。本系列默认已经可以将设备模拟成u盘,并且已经通过修改diskio.c,可以实现ff.c中的各项功能( 不能实现的自行面壁)。FatFS项目官网 http://elm-chan.org/f...
猜你喜欢
Mysql之锁与事务知识要点小结
Mysql之锁与事务 平时的业务中,顶多也就是写写简单的sql,连事务都用的少,对锁这一块的了解就更加欠缺了,之前一个大神分享了下mysql的事务隔离级别,感觉挺有意思的,正好发现一个很棒的博文,然后也收集了一些相关知识,正好来学习下,mysql中锁与事务的神秘面纱,主要内容包括 共享锁和排它锁的区别以及适合范围 mysql的表锁和行锁的区别 怎么判断一个sql是否执行了锁,执行的是表锁还是行锁 ...
响应式图片二 通过srcset实现
具体方法如下: srcset=”图片地址+空格+尺寸描述符,图片地址+空格+尺寸描述符,图片地址+空格+尺寸描述符….” 浏览器会当前浏览的环境进行感知,这个感知包括网速、界面分辨率、DPR(屏幕像素比)等等,然后在图片中选择一个进行加载。 实际上,在相同DPR下,浏览器会根据屏幕的分辨率加载图片,但是加载了大的图片后再缩小还是会使用大的图片。综合考虑的算法非...
Training_model(2)
已经清洗处理了两个数据文件: application_{train|test}.csv :客户详细信息 bureau.csv : 客户历史信用报告 下面对这两个数据中的特征进行合并,然后Light Gradient Boosting Machine训练模型,之前只用客户数据的预测评分结果是0.734,这次加入了客户信用报告信息 load data 新增加了客户历史信用记录 Build Model ...
微信小程序 页面跳转(传参跟不传参)
跳转页面传参 1.首先我的目录结构是这样的,并在 cinema.wxml 定义了一个点击事件 bindtap=‘indetai’ 2.然后在 cinema.js 的data里面定义了一个 score,并实现了 indetai 方法 3.在 detai.js 的 data 里面也定义一个 score ,再在 onLoad 函数里面接收传递过来的值 4.在页面上显示得到的值 这...
JavaSE 10(二维数组)
前言: 在经历了血雨腥风的地狱模式后本以为迎来了学习的平静,但二维数组又打破了这难得的平静!!!二维数组在java编程中同样也是很重要的知识点,因此在这里我将整理二维数组的知识点与重点,以及习题,便于自己的复习与巩固。 二维数组的声明与创建: 下面是声明二维数组的语法: 数据类型[][]数组名 : 数据类型数组名[][]; (允许这种方式 ,但并不推荐使用它...