java 基于servlet+maven+mybatis+websocket聊天,包括单聊和群聊
运行环境:jdk1.8
apache-tomcat-8.0.30
功能:发送文本、qq表情、图片、视频的组合消息,发送语音,语音支持(火狐,谷歌,ie,360等浏览器),发送附件消息并可以下载,消息撤回
对手机做单独的web页面适配。
运行效果图-电脑版:
单聊界面:
群聊界面:
手机端-效果图:
框架搭建:
1.新建maven项目
maven依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!-- mybatis包 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.18</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.27</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
<!-- log4j需要的jar包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.22</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.22</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier><!--指定jdk版本-->
</dependency>
<!-- servlet -->
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.7</version>
</dependency>
需要在build path中单独引入tomcat lib下面的websocket-api.jar 文件
2.在web.xml中配置session过滤器 ,用于登录超时跳转到登录页面
<filter>
<filter-name>SessionFilter</filter-name>
<filter-class>com.zkkj.chat.filter.SessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<url-pattern>/group/*</url-pattern>
<url-pattern>/loginSuccess/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
SessionFilter.java
import java.io.IOException;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class SessionFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
HttpSession session = request.getSession();
//判断sessin是否过期
Map userMap = (Map) session.getAttribute("userSession");
if(userMap == null){
//跳转至登录页面
response.sendRedirect("/chat/index");
}else{
arg2.doFilter(request, response);
}
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
3.在web.xml中配置监听器,用于项目启动后加载配置文件,启动定时器检测用户在线状态等操作
<listener>
<description>ServletContextListener</description>
<listener-class>com.zkkj.chat.listener.ContextInitListener</listener-class>
</listener>
ContextInitListener.java
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
public class ContextInitListener implements ServletContextListener {
private IUserService userService = new UserServiceImpl();
@Override
public void contextInitialized(ServletContextEvent sce) {
// TODO Auto-generated method stub
// 加载classpath下的配置文件
InputStream in = getClass().getClassLoader().getResourceAsStream("config.properties");
if(in == null){
return;
}
Properties prop = new Properties();
Map<String,String> propertiesMap=new HashMap<String, String>();
try {
prop.load(in);
Iterator<String> it=prop.stringPropertyNames().iterator();
while(it.hasNext()){
String key = it.next();
String value = prop.getProperty(key);
propertiesMap.put(key, value);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
PropertiesConfig.setPropertiesMap(propertiesMap);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// TODO Auto-generated method stub
}
}
项目启动后 进入ContextInitListener监听器 ,将config.properties文件内容读取到PropertiesConfig类中propertiesMap对象中,通过PropertiesConfig.get("");获取config.properties文件中的值
PropertiesConfig.java
import java.util.Map;
public class PropertiesConfig {
private static Map<String,String> propertiesMap;
public static String getProperties(String key){
return propertiesMap.get(key);
}
public static Map<String, String> getPropertiesMap() {
return propertiesMap;
}
public static void setPropertiesMap(Map<String, String> propertiesMap) {
PropertiesConfig.propertiesMap = propertiesMap;
}
}
config.properties
#websocket连接地址
websockt_url = wss://192.168.10.54:8443/chat/webSocket
#资源访问地址
return_path_z = https://192.168.10.54:8443/
#资源下载地址
return_path_z1 = http://192.168.10.54:8088/
#tomcat虚拟路径
#base_upload_path = /usr/local/data/
base_upload_path = D:/data/
#servlet 上传缓存路径
cache_path = cache/
#图片保存路径
image_path = image/
#文件保存路径
attachment_path = file/
#视频保存路径
video_path = video/
#语音保存路径
audio_path = audio/
#mysql 数据库连接
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/chat?useUnicode=true&autoReconnect=true&characterEncoding=utf-8
jdbc.username = root
jdbc.password = 123456
log4j.properties
log4j.configuration= log4j.properties
log4j.rootCategory=INFO,DLOGFILE,CONSOLE,ERROR
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=-%-d{yyyyMMdd-HH:mm:ss} %t %c %m%n
log4j.appender.DLOGFILE=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DLOGFILE.File=../logs/log.log
log4j.appender.DLOGFILE.Append=true
log4j.appender.DLOGFILE.DatePattern='.'yyyy-MM-dd
log4j.appender.DLOGFILE.Threshold=ALL
log4j.appender.DLOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.DLOGFILE.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} %m%n
log4j.logger.com.mybatis=DEBUG
log4j.logger.com.mybatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.mybatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.mybatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG</strong>
4.集成mybatis数据库操作
4.1 封装mybatis通用dao接口和实现类
IBaseDao.java
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.apache.poi.ss.formula.functions.T;
import com.zkkj.chat.util.Page;
public interface IBaseDao<T,PK extends Serializable> {
/**
* 插入对象
*/
int insert(String statementName,T obj);
/**
* 根据主键删除对象
*/
int delete(String statementName, PK primaryKey);
/**
* 根据条件删除
*/
int deleteByParam(String statementName,Map obj);
/**
* 更新实体
* @param entity
* @return
*/
int update(String statementName, T entity);
/**
* 根据条件更新
*/
int updateByParam(String statementName,Object obj);
T get(String statementName,PK primaryKey);
/**
* 查询单条数据
*/
T selectOneByParam(String statementName,Map obj);
/**
* 查询全部
* @param statementName
* @return
*/
List<T> selectList(String statementName);
/**
* 查询多条不分页
*/
List<T> selectList(String statementName,Map obj);
/**
* 查询多条分页
*/
List<T> selectList(String statementName,Map obj,Page page);
/**
* 查询总记录数
*/
int getCount(String statementName,Object obj);
/**
* 批量插入
* @param list
*/
int insertBatch(String statementName, final List<T> list);
/**
* 批量修改
* @param list
*/
int updateBatch(String statementName, final List<T> list);
/**
* 批量删除
* @param list
*/
int deleteBatch(String statementName, final List<PK> list);
}
BaseDaoImpl.java
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import com.zkkj.chat.util.MybatisUtil;
import com.zkkj.chat.util.Page;
public class BaseDaoImpl<T, PK extends Serializable> implements IBaseDao<T, PK> {
@Override
public int insert(String statementName, T obj) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
int count = 0;
try {
count = session.insert(statementName, obj);
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return count;
}
@Override
public int delete(String statementName, PK primaryKey) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
int count = 0;
try {
count = session.delete(statementName, primaryKey);
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return count;
}
@Override
public int deleteByParam(String statementName, Map obj) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
int count = 0;
try {
count = session.delete(statementName, obj);
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return count;
}
@Override
public int update(String statementName, T entity) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
int count = 0;
try {
count = session.update(statementName, entity);
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return count;
}
@Override
public int updateByParam(String statementName, Object obj) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
int count = 0;
try {
count = session.update(statementName, obj);
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return count;
}
@Override
public T get(String statementName, PK primaryKey) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
T object = null;
try {
object = session.selectOne(statementName, primaryKey);
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return object;
}
@Override
public T selectOneByParam(String statementName, Map obj) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
T object = null;
try {
object = session.selectOne(statementName, obj);
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return object;
}
@Override
public List<T> selectList(String statementName) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
List<T> list = null;
try {
list = session.selectList(statementName);
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return list;
}
@Override
public List<T> selectList(String statementName, Map obj) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
List<T> list = null;
try {
list = session.selectList(statementName, obj);
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return list;
}
@Override
public List<T> selectList(String statementName, Map obj,
Page page) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
List<T> list = null;
try {
list = session.selectList(statementName, obj, new RowBounds(page.getStartItem(),page.getNumPerPage()));
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return list;
}
@Override
public int getCount(String statementName, Object obj) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
int count = 0;
try {
count = session.selectOne(statementName,obj);
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return count;
}
@Override
public int insertBatch(String statementName, List<T> list) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
int count = 0;
try {
count = session.insert(statementName, list);
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return count;
}
@Override
public int updateBatch(String statementName, List<T> list) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
int count = 0;
try {
count = session.update(statementName, list);
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return count;
}
@Override
public int deleteBatch(String statementName, List<PK> list) {
// TODO Auto-generated method stub
SqlSession session = MybatisUtil.getSqlSession();
int count = 0;
try {
count = session.delete(statementName, list);
session.commit();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println(e.getMessage());
}finally{
MybatisUtil.closeSqlSession();
}
return count;
}
}
MybatisUtil.java
import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MybatisUtil {
private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();
private static SqlSessionFactory sqlSessionFactory;
/**
* 加载位于src/mybatis.xml配置文件
*/
static{
try {
Reader reader = Resources.getResourceAsReader("chat/mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 禁止外界通过new方法创建
*/
private MybatisUtil(){
}
/**
* 获取SqlSession
*/
public static SqlSession getSqlSession(){
//从当前线程中获取SqlSession对象
SqlSession sqlSession = threadLocal.get();
//如果SqlSession对象为空
if(sqlSession == null){
//在SqlSessionFactory非空的情况下,获取SqlSession对象
sqlSession = sqlSessionFactory.openSession();
//将SqlSession对象与当前线程绑定在一起
threadLocal.set(sqlSession);
}
//返回SqlSession对象
return sqlSession;
}
/**
* 关闭SqlSession与当前线程分开
*/
public static void closeSqlSession(){
//从当前线程中获取SqlSession对象
SqlSession sqlSession = threadLocal.get();
//如果SqlSession对象非空
if(sqlSession != null){
//关闭SqlSession对象
sqlSession.close();
//分开当前线程与SqlSession对象的关系,目的是让GC尽早回收
threadLocal.remove();
}
}
}
4.2 mybatis 配置数据源
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="config.properties"></properties>
<!-- 数据库配置信息 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="poolPingEnabled" value="true"/>
<property name="poolPingQuery" value="select 1"/>
<property name="poolPingConnectionsNotUsedFor" value="3600000"/>
</dataSource>
</environment>
</environments>
<!-- 映射文件 -->
<mappers>
<mapper resource="com/zkkj/chat/dao/UserInfoMapper.xml"/>
<mapper resource="com/zkkj/chat/dao/GroupInfoMapper.xml"/>
<mapper resource="com/zkkj/chat/dao/MessageInfoMapper.xml"/>
</mappers>
</configuration>
UserInfoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="userInfo" >
<!-- 查询广告商列表 -->
<select id="getUserList" parameterType="java.util.Map" resultType="java.util.Map">
select
*
from tb_user
where 1 = 1
<if test="account != null and account != ''">
and account = #{account}
</if>
<if test="nickName != null and nickName != ''">
and nickName = #{nickName}
</if>
<if test="password != null and password != ''">
and password = md5(#{password})
</if>
<if test="onlineStatus != null and onlineStatus != ''">
and onlineStatus = #{onlineStatus}
</if>
</select>
<select id="selectUserById" parameterType="java.util.Map" resultType="java.util.Map">
select * from tb_user
where id = #{userId}
</select>
<!-- 添加用户信息 -->
<insert id="addUser" parameterType="java.util.Map" useGeneratedKeys="true" keyProperty="id">
insert into tb_user(account,password,nickName,headUrl)
values (#{account},#{password},#{nickName},#{headUrl})
</insert>
<!-- 更新用户信息 -->
<update id="updateUser" parameterType="java.util.Map">
update tb_user
<set >
<if test="nickName != null and nickName != ''" >
nickName = #{nickName,jdbcType=VARCHAR},
</if>
<if test="onlineStatus != null and onlineStatus != ''">
onlineStatus = #{onlineStatus},
</if>
<if test="password != null and password != ''">
password = #{password},
</if>
</set>
where id = #{userId}
</update>
<!-- 删除用户 -->
<delete id="deleteUser" parameterType ="java.util.Map">
delete from tb_user where id = #{userId}
</delete>
</mapper>
框架搭建完毕!
前端jsp
1.首页index.jsp
项目启动后跳转到index.jsp页面,js判断浏览器的类型跳转到的不同的页面
判断浏览器是pc端还是移动端的方法如下:
<script type="text/javascript">
function IsPC() {
var userAgentInfo = navigator.userAgent;
var Agents = ["Android", "iPhone",
"SymbianOS", "Windows Phone",
"iPad", "iPod"];
var flag = true;
for (var v = 0; v < Agents.length; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}
function toUrl(){
if(IsPC()){
//跳转到电脑登登录页面
window.location.href="<%=path%>/index";
}else{
//跳转到手机登录页面
window.location.href="<%=path%>/index?dev=mobile";
}
}
</script>
</head>
<body onload="toUrl()">
</body>
2.建立socket连接
websocket_url为配置文件配置的socket连接地址,${fromUserId}为当前 用户登录的id。
jsp获取配置文件属性:
//引入java包的地址
<%@ page import="com.zkkj.chat.util.*,java.util.*,java.text.*"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ request.getContextPath() + "/";
//socket连接地址
String websockt_url = PropertiesConfig.getProperties("websockt_url");
//资源访问地址
String return_path_z = PropertiesConfig.getProperties("return_path_z");
%>
//socket初始化方法:
var socket;
function initSocket(){
console.log("dasdas");
socket = new WebSocket("<%=websockt_url%>?userId=${fromUserId}");
/*
*监听三种状态的变化 。js会回调
*/
socket.onopen = function(message) {
//客户端连接成功,向后台发送心跳检测,每隔10秒发送一次
setInterval(function (){
var json = {};
//定义json 发送消息
var json = {};
json.message = "";
json.extra = "";
json.messageType = "4";//心跳消息
json.type = "${type}";//心跳消息
json.fromUserId = "${fromUserId}";
json.toUserId = "";
json.groupId = "";
socket.send(JSON.stringify(json));
},3000);
};
socket.onclose = function(message) {
socket.close();
};
socket.onmessage = function(message) {
showMessage(message.data);
};
socket.onerror = function(message) {
socket.close();
};
}
3.消息输入框的设计
首先想到的肯定是textarea 但是textarea没法插入图片和视频,所以我才用的是可编辑的div来实现,在div添加contenteditable="true"属性 就变成了可编辑的div了。
<!-- 功能输入区域 -->
<div id="chatInputArea" style="width:100%;min-height:18px;border:0px solid blue;margin:5px 0 3px 0;margin:10px 0 0 10px;">
<div style="width:100%;min-height:30px;">
<div id="textMsg" style ="width:100%;height:100px; border : 1px solid #ccc;overflow:auto;border-radius:5px;" contenteditable="true">
</div>
</div>
</div>
4.消息展示框的设计
聊天页面整体布局
群聊消息都是默认以此从上往下面排列好布局,现在说说单聊的左右布局方式
首先设置一个默认的用户id就是当前登录的用户id
<c:set value="${userSession.id }" var="curUserId"></c:set>
然后再循环后台消息记录的时候 判断用户id和当前id是否相同,如果相同 就排列在右侧 ,如果不同就排列在左侧
在页面初始化完成消息内容的时候,需要将滚动条滚动到底部,显示最新的消息
$('#showChatMessage').animate({scrollTop: $('#showChatMessage')[0].scrollHeight + 'px'}, 1000);
在每次发送完消息之后 还是调用这个方法 进行重新滚动滚动条
对于手机页面 其他的不变,只需要将最外层的元素的固定宽度设置为100%自适应就可以了。
5.功能图标的设计
点击功能图标就能打开文件选择器 ,而不是直接用比较难看的文件选择器,可以采用间接的方式,在图片下面隐藏一个文件选择元素,当点击图片的时候,调用隐藏文件选择器的click方法就可以了。
<!-- 选择图片 -->
<img class="image" src="<%=path %>/chat/image/image.png" style="cursor:pointer;border:0px solid gray;padding:2px;" title="图片消息"/>
<div style="width:200px;height:30px;border:1px solid gray;background-color:white;position:absolute;margin:0 0 0 25px;display:none;">
<div style="width:100%;min-height:10px;">
<input id="file1" name="file1" type="file" value="" onchange="file1Upload()" style="height:30px;"/>
</div>
</div>
//当点击图片时触发 文件选择器
$(".image,.video,.attchment").click(function(){
$(this).next().find("input[type='file']").click();
});
6.文件上传插件
文件上传采用ajaxfileupload.js插件,需要引入插件库文件,上传后台返回文件的数据库保存路径和完整的url路径,将url拼接成图片或者视频html追加到消息输入框中,以文本的方式发送消息。
引入文件上传插件
<script type="text/javascript" src="<%=path %>/chat/js/ajaxfileupload.js"></script>
上面的file1Upload方法如下
//图片文件上传
function file1Upload(){
$("#sendBn").val("文件上传中...");
$("#sendBn").attr("disabled",true);
$.ajaxFileUpload({
url: '<%=path%>/resource?method=upload&fileType=image',
type: 'get',
async: 'false',
data : {
},
secureuri: false, //一般设置为false
fileElementId: 'file1', // 上传文件的name属性名
dataType: 'JSON', //返回值类;型,一般设置为json、application/json 这里要用大写 不然会取不到返回的数据
success: function(data, status){
var obj = $(data).removeAttr("style").prop("outerHTML");
data =obj.replace("<PRE>", '').replace("</PRE>", '').replace("<pre>", '').replace("</pre>", ''); //ajaxFileUpload会对服务器响应回来的text内容加上<pre>text</pre>前后缀
var json = JSON.parse(data);
if(json.result == "0"){
alert(json.message);
$("#sendBn").val("发送");
$("#sendBn").attr("disabled",false);
return false;
}
//在光标出添加上传的图片
addImage($("#textMsg"),'<img src="'+json.url+'" style="width:100px;">');
$(".image").next().slideUp(300);
$("#file1").val("");
/* $("#imageShow").html('<img src="'+json.url+'" style="width:100px;height:100px;">').show();
//保存图片路径到文本域中
$("#imageUrl").val(json.savePath); */
$("#sendBn").val("发送");
$("#sendBn").attr("disabled",false);
},
error: function(data, status, e){
alert("网络错误,请刷新后重新尝试!");
$("#sendBn").val("发送");
$("#sendBn").attr("disabled",false);
}
});
}
文件上传和下载代码的后台处理,servlet实现
ResourceServlet.java
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
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.JSONObject;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.zkkj.chat.util.PropertiesConfig;
/**
* Servlet implementation class ResourceServlet
*/
@WebServlet("/resource")
public class ResourceServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
final long MAX_SIZE = 1024 * 1024 * 1024;// 设置上传文件最大为 10M
/**
* @see HttpServlet#HttpServlet()
*/
public ResourceServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
Map resultMap = new HashMap();
String method = request.getParameter("method");
String fileType = request.getParameter("fileType");
//资源上传
if("upload".equals(method)){
response.setContentType("application/json; charset=utf-8");
// 设置字符编码为UTF-8, 这样支持汉字显示
response.setCharacterEncoding("UTF-8");
// 实例化一个硬盘文件工厂,用来配置上传组件ServletFileUpload
DiskFileItemFactory dfif = new DiskFileItemFactory();
dfif.setSizeThreshold(4096);// 设置上传文件时用于临时存放文件的内存大小,这里是4K.多于的部分将临时存在硬盘
ServletFileUpload sfu = new ServletFileUpload(dfif);
// 设置最大上传尺寸
sfu.setSizeMax(MAX_SIZE);
PrintWriter out = response.getWriter();
// 从request得到 所有 上传域的列表
List fileList = null;
try {
fileList = sfu.parseRequest(request);
} catch (FileUploadException e) {// 处理文件尺寸过大异常
if (e instanceof SizeLimitExceededException) {
resultMap.put("result", "0");
resultMap.put("message", "文件尺寸超过规定大小:"+MAX_SIZE+"字节");
out.write(JSONObject.fromObject(resultMap).toString());
return ;
}
e.printStackTrace();
}
// 没有文件上传
if (fileList == null || fileList.size() == 0) {
resultMap.put("result", "0");
resultMap.put("message", "请选择上传文件");
out.write(JSONObject.fromObject(resultMap).toString());
return ;
}
// 得到所有上传的文件
Iterator fileItr = fileList.iterator();
// 循环处理所有文件
while (fileItr.hasNext()) {
FileItem fileItem = null;
//文件大小
long size = 0;
//文件原始名称
String fileOldName = null;
//文件后缀
String suffix = null;
//文件的上传名称
String fileUploadName = null;
//文件的保存路径
String savePath = null;
//文件的完整保存路径
String path = null;
// 得到当前文件
fileItem = (FileItem) fileItr.next();
// 忽略简单form字段而不是上传域的文件域(<input type="text" />等)
if (fileItem == null || fileItem.isFormField()) {
continue;
}
//获取文件名称
fileOldName = fileItem.getName();
// 得到文件的大小
size = fileItem.getSize();
//文件扩展名称
suffix = fileOldName.substring(fileOldName.lastIndexOf("."), fileOldName.length());
//重新定义文件名称
Random random = new Random();
//文件的上传名称
fileUploadName = random.nextInt(10000)+ System.currentTimeMillis()+suffix;
//获取文件的上传的根目录
String base_upload_path = PropertiesConfig.getProperties("base_upload_path");
//资源的访问地址
String return_path_z = PropertiesConfig.getProperties("return_path_z");
switch (fileType) {
case "image":
{
if(
!".jpg".equals(suffix) && !".JPG".equals(suffix) && !".png".equals(suffix) && !".gif".equals(suffix)
){
resultMap.put("result", "0");
resultMap.put("message","请选择jpg,png,gif格式的图片");
out.write(JSONObject.fromObject(resultMap).toString());
return ;
}
//获取图片资源的上传目录
String image_path = PropertiesConfig.getProperties("image_path");
//文件保存到数据库的名称
savePath = image_path + fileUploadName;
//文件的完整保存路径
path = base_upload_path + savePath;
}
break;
case "attchment":
{
//附件文件
String attachment_path = PropertiesConfig.getProperties("attachment_path");
//文件上传名称
savePath = attachment_path + fileUploadName;
//文件的完整保存路径
path = base_upload_path + savePath;
}
break;
case "video":
{
if(
!".mp4".equals(suffix)
){
resultMap.put("result", "0");
resultMap.put("message","请选择mp4格式的视频");
out.write(JSONObject.fromObject(resultMap).toString());
return ;
}
//视频消息
String video_path = PropertiesConfig.getProperties("video_path");
//上传名称
savePath = video_path + fileOldName;
//文件完整的保存路径
path = base_upload_path + savePath;
}
break;
default:
break;
}
try {
File saveDir = new File(path);
if (!saveDir.getParentFile().exists())
saveDir.getParentFile().mkdirs();
// 保存文件
fileItem.write(new File(path));
response.setStatus(200);
//返回成功的消息
resultMap.put("result", "1");
resultMap.put("savePath", savePath);
resultMap.put("fileOldName", fileOldName);
resultMap.put("url",return_path_z + savePath);
DecimalFormat df = new DecimalFormat("#.00");
resultMap.put("fileSize", df.format(size / 1024));
out.write(JSONObject.fromObject(resultMap).toString());
return ;
} catch (Exception e) {
e.printStackTrace();
}
out.flush();
out.close();
}
}else if("download".equals(method)){
String path = request.getParameter("path");
String name = request.getParameter("name");
if(name.contains("(")){
name = name.substring(0, name.indexOf("("));
}
String return_path_z = PropertiesConfig.getProperties("return_path_z1");
//文件下载
response.setCharacterEncoding("utf-8");
response.setContentType("application/form-data");
String fileName = new String(name.getBytes("GB2312"), "ISO8859-1");
response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
response.setBufferSize(1024);
// 文件路径
URL url = new URL(return_path_z + path);
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
InputStream inputStream = connection.getInputStream();
OutputStream os = response.getOutputStream();
byte[] b = new byte[1024];
int length;
while ((length = inputStream.read(b)) > 0) {
os.write(b, 0, length);
}
inputStream.close();
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(request, response);
}
}
资源上传到固定的目录,而不是tomcat项目下的目录,需要配置虚拟路径,参考地址tomcat配置虚拟路径
7.发送语音
<!-- 引入录音文件 -->
<script type="text/javascript" src="<%=path %>/chat/plug/record/js/recordmp3.js"></script>
var mp3Blob;//录音后的MP3blob文件
var recorder = null;//全局的录音对象
//页面加载完成初始话录音插件
$(function(){
//初始化录音插件
recorder = new MP3Recorder({
debug:true,
funOk: function () {
},
funCancel: function (msg) {
recorder = null;
}
});
})
//开始录音
function funStart() {
if(recorder != null){
try{
recorder.start();
return true;
}catch(e){
alert(e);
return false;
}
}else{
alert("录音插件初始化失败");
return false;
}
}
//录音结束
function funStop() {
recorder.stop();
recorder.getMp3Blob(function (blob) {
mp3Blob = blob;
var reader = new FileReader();
reader.readAsDataURL(mp3Blob);
reader.onload = function(e){
funUpload(this.result);
}
// var url = URL.createObjectURL(mp3Blob);
// funUpload();
});
}
//录音文件base64格式上传
function funUpload(mp3Base64) {
var fd = new FormData();
fd.append('file', mp3Base64);
fd.append("name","张三");
$.ajax({
async: false,
url : "<%=path%>/base64Upload",
type : 'post',
data :fd,
processData : false, //必须false才会避开jQuery对 formdata 的默认处理
contentType : false, //必须false才会自动加上正确的Content-Type
dataType:"text",
success : function(result) {
//直接发送语音消息
var text = '<audio src="'+result+'" controls=""></audio>' ;
var json = {};
json.message = text;
json.extra = "";
json.messageType = "1";
json.type = "${type}";
json.fromUserId = "${fromUserId}";
json.toUserId = "${toUserId}";
json.groupId = "${groupId}";
socket.send(JSON.stringify(json));
},
error : function(result) {
}
});
}
//自己可以在点击语音图标开始录音的时候,添加动态录音gif图和读秒的效果,文件发送成功后隐藏读秒显示
//录音插件文件上传的后台处理,将base64转换成文件流保存到指定位置后,返回文件的访问地址,ajax返回前端在拿着地址拼接audio标签 发送消息。
FormDataServlet.java
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
import com.zkkj.chat.util.PropertiesConfig;
/**
* Servlet implementation class FormDataServlet
*/
@WebServlet("/base64Upload")
@MultipartConfig
public class FormDataServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public FormDataServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("application/text; charset=utf-8");
// 设置字符编码为UTF-8, 这样支持汉字显示
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
String file = new String (request.getParameter("file").getBytes("ISO8859-1"),"UTF-8"); //二进制流上传需要转码
file = file.replace("data:audio/mp3;base64,", "");//去掉base64前面的部分
//文件上传根目录
String base_upload_path = PropertiesConfig.getProperties("base_upload_path");
//文件访问路径
String return_path_z = PropertiesConfig.getProperties("return_path_z");
//文件保存路径
String audio_path = PropertiesConfig.getProperties("audio_path");
//重新定义文件名称
Random random = new Random();
//文件的上传名称
String fileUploadName = random.nextInt(10000)+ System.currentTimeMillis()+".mp3";
//文件保存路径
String savePath = audio_path + fileUploadName;
//文件完整路径
String filePath = base_upload_path + savePath;
base64ToIo(file,filePath);
// 返回文件地址
out.write(return_path_z+ savePath);
}
public void base64ToIo(String strBase64,String path) throws IOException {
File saveDir = new File(path);
if (!saveDir.getParentFile().exists())
saveDir.getParentFile().mkdirs();
String string = strBase64;
String fileName = path; //生成的新文件
try {
// 解码,然后将字节转换为文件
boolean flag = Base64.isBase64(strBase64);
byte[] bytes = Base64.decodeBase64(string); //将字符串转换为byte数组
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
byte[] buffer = new byte[1024];
for (int i = 0; i < buffer.length; ++i) {
if (buffer[i] < 0) {
// 调整异常数据
buffer[i] += 256;
}
}
FileOutputStream out = new FileOutputStream(fileName);
int bytesum = 0;
int byteread = 0;
while ((byteread = in.read(buffer)) != -1) {
bytesum += byteread;
out.write(buffer, 0, byteread); //文件写操作
}
out.flush();
out.close();
in.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
说明:浏览器为了安全考虑 有的限制了录音功能,没有限制的可能会每次进入页面都会提示获取权限,为了解决这个问题的最好办法 就是采用https的访问访问项目
,tomcat配置https的方法可以参考这个链接tomcat配置https
8.在输入框的光标出插入元素
在光标出添加内容的方法如下:
//在对象光标出插入元素,obj是要插入元素的jquery对象
function addImage(obj,text){
var range, node;
if(!obj.hasfocus) {
obj.focus();
}
if (window.getSelection && window.getSelection().getRangeAt) {
range = window.getSelection().getRangeAt(0);
range.collapse(false);
node = range.createContextualFragment(text);
var c = node.lastChild;
range.insertNode(node);
if(c){
range.setEndAfter(c);
range.setStartAfter(c)
}
var j = window.getSelection();
j.removeAllRanges();
j.addRange(range);
} else if (document.selection && document.selection.createRange) {
document.selection.createRange().pasteHTML(text);
}
}
如果不需要使用 可编辑的div方式的消息的输入框,使用简单的textarea文本输入框的话,在光标出插入的方法如下
//在光标出插入元素,t 为textarea 对象,例如document.getElementById("textMsg");
function addTextAtFocus(t, txt){
var val = t.value;
if(document.selection){
t.focus()
document.selection.createRange().text = txt;
} else {
var cp = t.selectionStart;
var ubbLength = t.value.length;
var s = t.scrollTop;
// document.getElementById('aaa').innerHTML += s + '<br />';
t.value = t.value.slice(0,t.selectionStart) + txt + t.value.slice(t.selectionStart, ubbLength);
this.setCursorPosition(t, cp + txt.length);
// document.getElementById('aaa').innerHTML += t.scrollTop + '<br />';
firefox=navigator.userAgent.toLowerCase().match(/firefox\/([\d\.]+)/) && setTimeout(function(){
if(t.scrollTop != s) t.scrollTop=s;
},0)
};
}
9.发送消息
//发送文本消息
function sendText() {
if (!socket || socket.readyState != 1) {
initSocket();
}
//获取消息输入框输入的内容并且去除掉空格
var text = $("#textMsg").html().trim();
if(text == null || text == ""){
alert("请输入消息内容!");
return false;
}
//定义json 发送消息
var json = {};
json.message = text;//消息内容
json.extra = "";//消息附加的信息
json.messageType = "1";//消息类型,1.文本消息,2.附件消息,3.语音消息 等等
json.type = "${type}"; //聊天类型,1.单聊,2.群聊
json.fromUserId = "${fromUserId}";//消息发送者的id
json.toUserId = "${toUserId}";//消息接受者的id ,如果type = 2群聊为空,
json.groupId = "${groupId}";//群组id,当type=1单聊 为空
socket.send(JSON.stringify(json)); //将json转换为字符串并发送给服务端
$("#textMsg").html("");//清空输入框的内容
}
按ENTER键发送消息
$("body").keydown(function(event) {
if (event.keyCode == "13") {//keyCode=13是回车键并且是文本消息的时候触发
sendText();
//避免换行
event.preventDefault();
}
});
10.接受服务端发送的消息
// 接收到服务器发送的消息方法
function showMessage(message) {
//解析消息json
var json = eval('(' + message + ')');
var text = '';//用于显示的消息html 内容
if(json.chatType == '${type}'){//后台传过来的聊天类型和当前聊天类型一样的时候才显示消息,因为单聊和群聊是一个页面 当然也可以分开为两个
text = getMsgContent(json);//getMsgContent方法为拼接消息内容的方法 ,自行处理
$("#showChatMessage").append(text);//将消息追加到显示区域下面
document.getElementById('showChatMessage').scrollTop = 100000;//滚动div的滚动条
//初始化消息撤回事件,鼠标放上面显示撤回按钮
initMsgRecall();
}
}
11.消息撤回
消息撤回的实现原理 ,当点击消息撤回的按钮 向服务器发送消息 消息类型为撤回的 然后根据聊天的类型是单聊还是群聊,给单个人或者群组所有的人发送系统消息为消息撤回的消息,前端收到系统消息后移除队形的消息内容并且显示系统消息内容。
//初始化消息撤回按钮事件
function initMsgRecall(){
//对未绑定hover的消息元素添加hover事件
$(".msgContent[initHover='0']").hover(function(){
//消息发送的时间
var msgDate = $(this).attr("msgDate");
//消息id
var msgId = $(this).attr("msgId");
//消息发送者
var fromUserId = $(this).attr("fromUserId");
//取到当前时间
var now = new Date();
var t = (new Date()).format("yyyy-MM-dd hh:mm:ss")
//当前时间与消息发送时间的间隔
var diff = GetDateDiff(msgDate,t, "minute");
//消息发送时间 小于三分钟,并且是自己发送的消息可以撤销
if(fromUserId == "${fromUserId}" && diff <= 3){
$(this).find("div:last").append('<span class="recall" style="margin-left:10px;"><a href="javascript:void();" onclick="recallMsg('+msgId+')">撤回</a></span>');
}
},function(){
//移除撤回按钮
$(this).find(".recall").remove();
});
//标记为已经初始化了hover事件
$(".msgContent").attr("initHover","1");
}
后台相关逻辑
Websocket.java
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import net.sf.json.JSONObject;
import com.zkkj.chat.service.IGroupService;
import com.zkkj.chat.service.IMessageService;
import com.zkkj.chat.service.IUserService;
import com.zkkj.chat.service.impl.GroupServiceImpl;
import com.zkkj.chat.service.impl.MessageServiceImpl;
import com.zkkj.chat.service.impl.UserServiceImpl;
import com.zkkj.chat.util.DateUtil;
import com.zkkj.chat.util.ParamsUtil;
import com.zkkj.chat.util.TimeFormatUtil;
@ServerEndpoint(value="/webSocket")
public class Websocket {
private IUserService service = new UserServiceImpl();
private IGroupService groupService = new GroupServiceImpl();
private IMessageService messageService = new MessageServiceImpl();
//保存所有的连接的客户端对象
static Map<String, Session> clientsMap = new ConcurrentHashMap<String, Session>();
//心跳检测 map
static Map<String, Long> heartMap = new HashMap<String, Long>();
// 与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
/*
*使用@Onopen注解的表示当客户端链接成功后的回掉。参数Session是可选参数
这个Session是WebSocket规范中的会话,表示一次会话。并非HttpSession
*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
Map params = session.getRequestParameterMap();
String userId = "";
Object userIdObject = params.get("userId");
if (userIdObject != null) {
userId = ((List<String>)userIdObject).get(0);
clientsMap.put(userId, session);
session.getUserProperties().put("userId", userId);
}
try {
//修改用户的在线状态
Map userUpdateParamsMap = new HashMap();
userUpdateParamsMap.put("onlineStatus", "1");
userUpdateParamsMap.put("userId", userId);
service.updateUser(userUpdateParamsMap);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
*用户断开链接后的回调,注意这个方法必须是客户端调用了断开链接方法后才会回调
*/
@OnClose
public void onClose(Session session) {
Map params = session.getRequestParameterMap();
String userId = "";
Object userIdObject = params.get("userId");
if (userIdObject != null) {
userId = ((List<String>)userIdObject).get(0);
}
clientsMap.remove(userId);
try {
session.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
//修改用户的在线状态
Map userUpdateParamsMap = new HashMap();
userUpdateParamsMap.put("onlineStatus", "0");
userUpdateParamsMap.put("userId", userId);
service.updateUser(userUpdateParamsMap);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@OnMessage
public void onMessage(String message,Session session){
JSONObject json = JSONObject.fromObject(message);
String type = json.getString("type");
String message_ = json.getString("message");
String fromUserId = json.getString("fromUserId");
String toUserId = json.getString("toUserId");
String goupId = json.getString("groupId");
String messageType = json.getString("messageType");//消息类型
String extra = json.getString("extra");//额外属性
if("1".equals(type)){
//单聊
try {
if("1".equals(messageType) || "3".equals(messageType)){
sendMessageToOne("",fromUserId,toUserId,message_,false,messageType,extra);
}else if("4".equals(messageType)){
//更新用户id的心跳时间
heartMap.put(fromUserId,new Date().getTime());
}else if("5".equals(messageType)){
//撤回消息
String msgId = json.getString("msgId");
//撤回 消息
sendMessageToOne(msgId,fromUserId,toUserId,message_,true,messageType,extra);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("单聊失败==========================" + e.getMessage());
}
}else if("2".equals(type)){
//群聊
try {
if("1".equals(messageType) || "3".equals(messageType)){
sendGroupMessage("",fromUserId, goupId, message_,false,messageType,extra);
}else if("4".equals(messageType)){
//更新用户id的心跳时间
heartMap.put(fromUserId,new Date().getTime());
}else if("5".equals(messageType)){
//撤回消息
String msgId = json.getString("msgId");
sendGroupMessage(msgId,fromUserId, goupId, message_,true,messageType,extra);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("群聊失败==========================" + e.getMessage());
}
}
}
//点对点消息
public void sendMessageToOne(String msgId_,String fromUserId, String toUserId,String message,boolean isSystem,String messageType,String extra) throws Exception{
if(!"".equals(toUserId) && toUserId != null){
//
Session fromUserSession = clientsMap.get(fromUserId);
Session toUserSession = clientsMap.get(toUserId);
//查询消息发送者的用户信息
Map params = new HashMap();
params.put("userId", fromUserId);
Map fromUser = service.getUserById(params);
//消息发送者的昵称
String fromUserNickName = "";
String fromUserHeadUrl = "";
if(fromUser != null){
fromUserNickName = ParamsUtil.nullDeal(fromUser, "nickName", "");
fromUserHeadUrl = ParamsUtil.nullDeal(fromUser, "headUrl", "");
}
JSONObject messageJson = new JSONObject();
messageJson.put("message", message);
messageJson.put("fromUserId", fromUserId);
messageJson.put("toUserId", toUserId);
messageJson.put("headUrl", fromUserHeadUrl);
messageJson.put("nickName", fromUserNickName);
messageJson.put("chatType", "1");//单聊
messageJson.put("messageType",messageType);//消息类型
messageJson.put("isSystem", isSystem);//是否是系统消息
messageJson.put("extra", extra);//附加属性
messageJson.put("msgDate", DateUtil.getStringDate());//消息发送的日期
messageJson.put("dateShow", TimeFormatUtil.getInterval(DateUtil.strToDateLong(DateUtil.getStringDate())));//消息发送时间,用于显示
String msgId = "";
try {
if(!"4".equals(messageType)){
//保存消息到数据库
Map addMessageParamsMap = new HashMap();
addMessageParamsMap.put("fromUserId", fromUserId);
addMessageParamsMap.put("toUserId", toUserId);
addMessageParamsMap.put("chatType", "1");
addMessageParamsMap.put("messageType",messageType);
addMessageParamsMap.put("content", message);
addMessageParamsMap.put("extra", extra);
messageService.addMessage(addMessageParamsMap);
//得到消息的id
msgId = String.valueOf(addMessageParamsMap.get("id"));
}
if("5".equals(messageType)){
//消息撤回,返回消息撤回的id
msgId = msgId_;
//删除消息内容
Map deleteMessageParamsMap = new HashMap();
deleteMessageParamsMap.put("msgId", msgId);
messageService.deleteMessage(deleteMessageParamsMap);
}
//设置消息id
messageJson.put("msgId", msgId);
//发送消息
if(fromUserSession != null){
//给发送消息着推送消息
fromUserSession.getBasicRemote().sendText(messageJson.toString());
}
if(toUserSession != null){
//给接受消息着推送消息
toUserSession.getBasicRemote().sendText(messageJson.toString());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//群聊消息
public void sendGroupMessage(String msgId_,String fromUserId,String groupId,String message,boolean isSystem,String messageType,String extra) throws Exception{
//查询消息发送者的用户信息
Map fromUserParams = new HashMap();
fromUserParams.put("userId", fromUserId);
Map fromUser = service.getUserById(fromUserParams);
//消息发送者的昵称
String fromUserNickName = "";
String fromUserHeadUrl = "";
if(fromUser != null){
fromUserNickName = ParamsUtil.nullDeal(fromUser, "nickName", "");
fromUserHeadUrl = ParamsUtil.nullDeal(fromUser, "headUrl", "");
}
JSONObject messageJson = new JSONObject();
messageJson.put("message", message);//消息内容
messageJson.put("fromUserId", fromUserId);//消息发送者
messageJson.put("groupId", groupId);//群组id
messageJson.put("headUrl", fromUserHeadUrl);//消息发送者的用户头像
messageJson.put("nickName", fromUserNickName);//消息发送者的用户昵称
messageJson.put("chatType", "2");//群聊
messageJson.put("messageType",messageType);//消息类型
messageJson.put("isSystem", isSystem);//是否是系统消息
messageJson.put("extra", extra);//附加属性
messageJson.put("msgDate", DateUtil.getStringDate());//消息发送的日期
messageJson.put("dateShow", TimeFormatUtil.getInterval(DateUtil.strToDateLong(DateUtil.getStringDate())));//消息发送时间,用于显示
//保存消息内容到数据库
String msgId = "";
if(!"4".equals(messageType)){
//保存消息到数据库
Map addMessageParamsMap = new HashMap();
addMessageParamsMap.put("fromUserId", fromUserId);
addMessageParamsMap.put("chatType", "2");
addMessageParamsMap.put("messageType",messageType);
addMessageParamsMap.put("groupId",groupId);
addMessageParamsMap.put("content", message);
addMessageParamsMap.put("extra", extra);
messageService.addMessage(addMessageParamsMap);
msgId = String.valueOf(addMessageParamsMap.get("id"));
}
if("5".equals(messageType)){
//消息撤回
msgId = msgId_;
//删除消息内容
Map deleteMessageParamsMap = new HashMap();
deleteMessageParamsMap.put("msgId", msgId);
messageService.deleteMessage(deleteMessageParamsMap);
}
//设置消息id
messageJson.put("msgId", msgId);
//根据群组id查询群成员
Map params = new HashMap();
params.put("groupId", groupId);
List<Map> userList = groupService.getGroupUserList(params);
//循环给群成员发送消息
for(Map user_ : userList){
Session session =clientsMap.get(String.valueOf(user_.get("id")));
if(session != null){
session.getAsyncRemote().sendText(messageJson.toString());
}
}
}
public static Map<String, Long> getHeartMap() {
return heartMap;
}
public static void setHeartMap(Map<String, Long> heartMap) {
Websocket.heartMap = heartMap;
}
}
DateUtil.java
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Random;
import org.apache.commons.lang.time.DateUtils;
/**
*@Title:
*@Description:日期处理类
*@Author:赵亚龙
*@Since:2016年2月28日
*@Version:1.1.0
*/
public class DateUtil {
/**
* yyyy-MM-dd HH:mm:ss
*/
public final static String FORMAT_GENERAL = "yyyy-MM-dd HH:mm:ss";
/**
* yyyy-MM-dd
*/
public final static String FORMAT_GENERAL1 = "yyyy-MM-dd";
/**
* MM/dd
*/
public final static String FORMAT_GENERAL2 = "MM/dd";
/**
* HH:mm
*/
public final static String FORMAT_GENERAL3 = "HH:mm";
/**
* yyyy-MM-dd HH:mm
*/
public final static String FORMAT_GENERAL4 = "yyyy-MM-dd";
/**
* MM-dd
*/
public final static String FORMAT_GENERAL5 = "MM-dd";
/**
* HH:mm MM-dd
*/
public final static String FORMAT_GENERAL6 = "HH:mm MM-dd";
/**
* MM-dd
*/
public final static String FORMAT_FLIGHT_PLAN = "HHmm";
/**
* 早上8点到下午16点,每隔半小时(一共是16个半小时)
*/
public final static int EIGHTH_TO_SIXTEEN = 16;
/**
* 获取12小时制当前日期字符串
*
* @return
*/
public static String getStrDate_12() {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date currentTime = new Date();
String strDate = formatter.format(currentTime);
return strDate;
}
/**
* 获取24小时制当前日期字符串
*
* @return
*/
public static String getStrDate_24() {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date currentTime = new Date();
String strDate = formatter.format(currentTime);
return strDate;
}
/**
* 获取格式化当前时间、毫秒字符串
*
* @return
*/
public static String getStrDateS() {
SimpleDateFormat formatter = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss:SS");
Date currentTime = new Date();
String strDate = formatter.format(currentTime);
return strDate;
}
/**
* 转换日期为字符串格式
* <p>
*
* @param Date
* @return
*/
public static String DateToStr(java.util.Date Date) {
if(Date != null){
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_GENERAL);
String strDate = formatter.format(Date);
return strDate;
}
return "";
}
/**
* 奖date类型的日期转换为指定格式
*/
public static Date DateToDate(java.util.Date Date, String format) {
SimpleDateFormat formatter = new SimpleDateFormat(format);
Date d = new Date();
String dd = formatter.format(d);
Date ddd = null;
try {
ddd = formatter.parse(dd);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ddd;
}
/**
* 转换日期为格式化字符串
*
* @param Date
* @param format
* @return
*/
public static String DateToFormatStr(java.util.Date Date, String format) {
SimpleDateFormat formatter = new SimpleDateFormat(format);
String strDate = formatter.format(Date);
return strDate;
}
/**
* 获取当前日期 格式为 yyyy-MM-dd
*
* @return strDate
*/
public static String getNowStrDate() {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date date = new Date();
String strDate = formatter.format(date);
return strDate;
}
/**
* 获取当间时间字符串 yyyyMMddHHmmss
*
* @return
*/
public static String getLongDate() {
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
Date date = new Date();
String strDate = formatter.format(date);
return strDate;
}
/**
* 获取当间时间字符串 yyyyMMddHHmmssSS
*
* @return
*/
public static String getLongDateS() {
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmssSS");
Date date = new Date();
String strDate = formatter.format(date);
return strDate;
}
/**
* 比较二个日期
*
* @param date1
* @param date2
* @return
*/
public static boolean Compare_Date(java.util.Date date1,
java.util.Date date2) {
return date1.equals(date2);
}
/**
* 将字符串类型的时间转化为Date型
*
* @param strDate
* @param formatDate
* @return Date
* @throws ParseException
*/
public static Date str2Date(String strDate, String formatDate)
throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat(formatDate);
return sdf.parse(strDate);
}
/**
* 将字符串类型的时间转化为Date型,并将在此时间上进行增加或减少相应天
*
* @param strDate
* @param formatDate
* @return Date
* @throws ParseException
*/
public static Date otherDate(String strDate, String formatDate, int num)
throws ParseException {
Calendar c = new GregorianCalendar();
Date date = str2Date(strDate, formatDate);
c.setTime(date);
c.add(Calendar.DATE, num);
SimpleDateFormat sdf = new SimpleDateFormat(formatDate);
return str2Date(sdf.format(c.getTime()), formatDate);
}
/**
* 获取现在时间
*
* @return 返回时间类型 yyyy-MM-dd HH:mm:ss
*/
public static Date getNowDate() {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(currentTime);
ParsePosition pos = new ParsePosition(8);
Date currentTime_2 = formatter.parse(dateString, pos);
return currentTime_2;
}
/**
* 获取现在时间
*
* @return返回短时间格式 yyyy-MM-dd
*/
public static Date getNowDateShort() {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String dateString = formatter.format(currentTime);
ParsePosition pos = new ParsePosition(8);
Date currentTime_2 = formatter.parse(dateString, pos);
return currentTime_2;
}
/**
* 获取现在时间
*
* @return返回字符串格式 yyyy-MM-dd HH:mm:ss
*/
public static String getStringDate() {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(currentTime);
return dateString;
}
/**
* 获取现在时间
*
* @return 返回短时间字符串格式yyyy-MM-dd
*/
public static String getStringDateShort() {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String dateString = formatter.format(currentTime);
return dateString;
}
/**
* 获取时间 小时:分;秒 HH:mm:ss
*
* @return
*/
public static String getTimeShort() {
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
Date currentTime = new Date();
String dateString = formatter.format(currentTime);
return dateString;
}
/**
* 将长时间格式字符串转换为时间 yyyy-MM-dd HH:mm:ss
*
* @param strDate
* @return
*/
public static Date strToDateLong(String strDate) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ParsePosition pos = new ParsePosition(0);
Date strtodate = formatter.parse(strDate, pos);
return strtodate;
}
/**
* 将长时间格式时间转换为字符串 yyyy-MM-dd HH:mm:ss
*
* @param dateDate
* @return
*/
public static String dateToStrLong(java.util.Date dateDate) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(dateDate);
return dateString;
}
/**
* 将短时间格式时间转换为字符串 yyyy-MM-dd
*
* @param dateDate
* @param k
* @return
*/
public static String dateToStr(java.util.Date dateDate) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String dateString = formatter.format(dateDate);
return dateString;
}
/**
* 将短时间格式字符串转换为时间 yyyy-MM-dd
*
* @param strDate
* @return
*/
public static Date strToDate(String strDate) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
ParsePosition pos = new ParsePosition(0);
Date strtodate = formatter.parse(strDate, pos);
return strtodate;
}
/**
* 得到现在时间
*
* @return
*/
public static Date getNow() {
Date currentTime = new Date();
return currentTime;
}
/**
* 提取一个月中的最后一天
*
* @param day
* @return
*/
public static Date getLastDate(long day) {
Date date = new Date();
long date_3_hm = date.getTime() - 3600000 * 34 * day;
Date date_3_hm_date = new Date(date_3_hm);
return date_3_hm_date;
}
/**
* 得到现在时间
*
* @return 字符串 yyyyMMdd HHmmss
*/
public static String getStringToday() {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd HHmmss");
String dateString = formatter.format(currentTime);
return dateString;
}
/**
* 得到现在小时
*/
public static String getHour() {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(currentTime);
String hour;
hour = dateString.substring(11, 13);
return hour;
}
/**
* 得到现在分钟
*
* @return
*/
public static String getTime() {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(currentTime);
String min;
min = dateString.substring(14, 16);
return min;
}
/**
* 根据用户传入的时间表示格式,返回当前时间的格式 如果是yyyyMMdd,注意字母y不能大写。
*
* @param sformat
* yyyyMMddhhmmss
* @return
*/
public static String getUserDate(String sformat) {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat(sformat);
String dateString = formatter.format(currentTime);
return dateString;
}
/**
* 二个小时时间间的差值,必须保证二个时间都是"HH:MM"的格式,返回字符型的分钟
*/
public static String getTwoHour(String st1, String st2) {
String[] kk = null;
String[] jj = null;
kk = st1.split(":");
jj = st2.split(":");
if (Integer.parseInt(kk[0]) < Integer.parseInt(jj[0]))
return "0";
else {
double y = Double.parseDouble(kk[0]) + Double.parseDouble(kk[1])
/ 60;
double u = Double.parseDouble(jj[0]) + Double.parseDouble(jj[1])
/ 60;
if ((y - u) > 0)
return y - u + "";
else
return "0";
}
}
/**
* 得到二个日期间的间隔天数
*/
public static String getTwoDay(String sj1, String sj2) {
SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");
long day = 0;
try {
java.util.Date date = myFormatter.parse(sj1);
java.util.Date mydate = myFormatter.parse(sj2);
day = (date.getTime() - mydate.getTime()) / (24 * 60 * 60 * 1000);
} catch (Exception e) {
return "";
}
return day + "";
}
/**
* 时间前推或后推分钟,其中JJ表示分钟.
*/
public static String getPreTime(String sj1, String jj) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String mydate1 = "";
try {
Date date1 = format.parse(sj1);
long Time = (date1.getTime() / 1000) + Integer.parseInt(jj) * 60;
date1.setTime(Time * 1000);
mydate1 = format.format(date1);
} catch (Exception e) {
}
return mydate1;
}
/**
* 得到一个时间延后或前移几天的时间,nowdate为时间,delay为前移或后延的天数
*/
public static String getNextDay(String nowdate, String delay) {
try {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String mdate = "";
Date d = strToDate(nowdate);
long myTime = (d.getTime() / 1000) + Integer.parseInt(delay) * 24
* 60 * 60;
d.setTime(myTime * 1000);
mdate = format.format(d);
return mdate;
} catch (Exception e) {
return "";
}
}
/**
* 判断是否润年
*
* @param ddate
* @return
*/
public static boolean isLeapYear(String ddate) {
/**
* 详细设计: 1.被400整除是闰年,否则: 2.不能被4整除则不是闰年 3.能被4整除同时不能被100整除则是闰年
* 3.能被4整除同时能被100整除则不是闰年
*/
Date d = strToDate(ddate);
GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
gc.setTime(d);
int year = gc.get(Calendar.YEAR);
if ((year % 400) == 0)
return true;
else if ((year % 4) == 0) {
if ((year % 100) == 0)
return false;
else
return true;
} else
return false;
}
/**
* 返回美国时间格式 26 Apr 2006
*
* @param str
* @return
*/
public static String getEDate(String str) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
ParsePosition pos = new ParsePosition(0);
Date strtodate = formatter.parse(str, pos);
String j = strtodate.toString();
String[] k = j.split(" ");
return k[2] + k[1].toUpperCase() + k[5].substring(2, 4);
}
/**
* 获取一个月的最后一天
*
* @param dat
* @return
*/
public static String getEndDateOfMonth(String dat) {// yyyy-MM-dd
String str = dat.substring(0, 8);
String month = dat.substring(5, 7);
int mon = Integer.parseInt(month);
if (mon == 1 || mon == 3 || mon == 5 || mon == 7 || mon == 8
|| mon == 10 || mon == 12) {
str += "31";
} else if (mon == 4 || mon == 6 || mon == 9 || mon == 11) {
str += "30";
} else {
if (isLeapYear(dat)) {
str += "29";
} else {
str += "28";
}
}
return str;
}
/**
* 判断二个时间是否在同一个周
*
* @param date1
* @param date2
* @return
*/
public static boolean isSameWeekDates(Date date1, Date date2) {
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal1.setTime(date1);
cal2.setTime(date2);
int subYear = cal1.get(Calendar.YEAR) - cal2.get(Calendar.YEAR);
if (0 == subYear) {
if (cal1.get(Calendar.WEEK_OF_YEAR) == cal2
.get(Calendar.WEEK_OF_YEAR))
return true;
} else if (1 == subYear && 11 == cal2.get(Calendar.MONTH)) {
// 如果12月的最后一周横跨来年第一周的话则最后一周即算做来年的第一周
if (cal1.get(Calendar.WEEK_OF_YEAR) == cal2
.get(Calendar.WEEK_OF_YEAR))
return true;
} else if (-1 == subYear && 11 == cal1.get(Calendar.MONTH)) {
if (cal1.get(Calendar.WEEK_OF_YEAR) == cal2
.get(Calendar.WEEK_OF_YEAR))
return true;
}
return false;
}
/**
* 获得一个日期所在的周的星期几的日期,如要找出2002年2月3日所在周的星期一是几号
*
* @param sdate
* @param num
* @return
*/
public static String getWeek(String sdate, String num) {
// 再转换为时间
Date dd = DateUtil.strToDate(sdate);
Calendar c = Calendar.getInstance();
c.setTime(dd);
if (num.equals("1")) // 返回星期一所在的日期
c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
else if (num.equals("2")) // 返回星期二所在的日期
c.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY);
else if (num.equals("3")) // 返回星期三所在的日期
c.set(Calendar.DAY_OF_WEEK, Calendar.WEDNESDAY);
else if (num.equals("4")) // 返回星期四所在的日期
c.set(Calendar.DAY_OF_WEEK, Calendar.THURSDAY);
else if (num.equals("5")) // 返回星期五所在的日期
c.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
else if (num.equals("6")) // 返回星期六所在的日期
c.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
else if (num.equals("0")) // 返回星期日所在的日期
c.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
return new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
}
/**
* 根据一个日期,返回是星期几的字符串
*
* @param sdate
* @return
*/
public static String getWeek(String sdate) {
// 再转换为时间
Date date = DateUtil.strToDate(sdate);
Calendar c = Calendar.getInstance();
c.setTime(date);
// int hour=c.get(Calendar.DAY_OF_WEEK);
// hour中存的就是星期几了,其范围 1~7
// 1=星期日 7=星期六,其他类推
return new SimpleDateFormat("EEEE").format(c.getTime());
}
public static String getWeekStr(String sdate) {
String str = "";
str = DateUtil.getWeek(sdate);
if ("1".equals(str)) {
str = "星期日";
} else if ("2".equals(str)) {
str = "星期一";
} else if ("3".equals(str)) {
str = "星期二";
} else if ("4".equals(str)) {
str = "星期三";
} else if ("5".equals(str)) {
str = "星期四";
} else if ("6".equals(str)) {
str = "星期五";
} else if ("7".equals(str)) {
str = "星期六";
}
return str;
}
/**
* 两个时间之间的天数
*
* @param date1
* @param date2
* @return
*/
public static long getDays(String date1, String date2) {
if (date1 == null || date1.equals(""))
return 0;
if (date2 == null || date2.equals(""))
return 0;
// 转换为标准时间
SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date date = null;
java.util.Date mydate = null;
try {
date = myFormatter.parse(date1);
mydate = myFormatter.parse(date2);
} catch (Exception e) {
}
long day = (date.getTime() - mydate.getTime()) / (24 * 60 * 60 * 1000);
return day;
}
/**
* 形成如下的日历 , 根据传入的一个时间返回一个结构 星期日 星期一 星期二 星期三 星期四 星期五 星期六 下面是当月的各个时间
* 此函数返回该日历第一行星期日所在的日期
*
* @param sdate
* @return
*/
public static String getNowMonth(String sdate) {
// 取该时间所在月的一号
sdate = sdate.substring(0, 8) + "01";
// 得到这个月的1号是星期几
Date date = DateUtil.strToDate(sdate);
Calendar c = Calendar.getInstance();
c.setTime(date);
int u = c.get(Calendar.DAY_OF_WEEK);
String newday = DateUtil.getNextDay(sdate, (1 - u) + "");
return newday;
}
/**
* 取得数据库主键 生成格式为yyyymmddhhmmss+k位随机数
*
* @param k
* 表示是取几位随机数,可以自己定
*/
public static String getNo(int k) {
return getUserDate("yyyyMMddhhmmss") + getRandom(k);
}
/**
*
* 获得当前时间的后多少天
*
* @param curr
* @param count
* @return
*/
public static Date getNextDate(Date curr, int count) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(curr);
calendar.add(Calendar.DAY_OF_MONTH, count);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date=null;
try {
date= str2Date(sdf.format(calendar.getTime()),"yyyy-MM-dd");
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
/**
* 返回一个随机数
*
* @param i
* @return
*/
public static String getRandom(int i) {
Random jjj = new Random();
// int suiJiShu = jjj.nextInt(9);
if (i == 0)
return "";
String jj = "";
for (int k = 0; k < i; k++) {
jj = jj + jjj.nextInt(9);
}
return jj;
}
/**
*
* @param args
*/
public static boolean RightDate(String date) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
;
if (date == null)
return false;
if (date.length() > 10) {
sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
} else {
sdf = new SimpleDateFormat("yyyy-MM-dd");
}
try {
sdf.parse(date);
} catch (ParseException pe) {
return false;
}
return true;
}
/**
* 返回两个年份的差值,多少年保留一位小数 prram yyyy-MM-dd
*/
public static String timeToTime(String startdate, String enddate) {
String date1[] = startdate.split("-");
int year1 = 365;
int month1 = 31;
int day1 = Integer.parseInt(date1[2]);
Long totalday1;
String date2[] = enddate.split("-");
int year2 = 365;
int month2 = 31;
int day2 = Integer.parseInt(date2[2]);
Long totalday2;
float time;
if ("04".equals(date1[2]) || "06".equals(date1[2])
|| "09".equals(date1[2]) || "11".equals(date1[2])) {
month1 = 30;
}
if ("02".equals(date1[2])) {
if (isLeapYear(startdate)) {
month1 = 29;
} else {
month1 = 28;
}
}
if ("04".equals(date2[2]) || "06".equals(date2[2])
|| "09".equals(date2[2]) || "11".equals(date2[2])) {
month2 = 30;
}
if ("02".equals(date2[2])) {
if (isLeapYear(enddate)) {
month2 = 29;
} else {
month2 = 28;
}
}
totalday1 = Long.parseLong(date1[0]) * year1
+ Integer.parseInt(date1[1]) * month1 + day1;
totalday2 = Long.parseLong(date2[0]) * year2
+ Integer.parseInt(date2[1]) * month2 + day2;
time = (float) (totalday1 - totalday2) / 365;
DecimalFormat df = new DecimalFormat("0.0");// 格式化小数,不足的补0
return df.format(time);// 返回的是String类型的
}
/**
* @param date1 需要比较的时间 不能为空(null),需要正确的日期格式 ,如:2009-09-12
* @param date2 被比较的时间 为空(null)则为当前时间
* @param stype 返回值类型 0为多少天,1为多少个月,2为多少年
* @return
* 举例:
* compareDate("2009-09-12", null, 0);//比较天
* compareDate("2009-09-12", null, 1);//比较月
* compareDate("2009-09-12", null, 2);//比较年
*/
public static int compareDate(String startDay,String endDay,int stype){
int n = 0;
String[] u = {"天","月","年"};
String formatStyle = stype==1?"yyyy-MM":"yyyy-MM-dd";
endDay = endDay==null?getNowStrDate():endDay;
DateFormat df = new SimpleDateFormat(formatStyle);
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
try {
c1.setTime(df.parse(startDay));
c2.setTime(df.parse(endDay));
} catch (Exception e3) {
System.out.println("wrong occured");
}
//List list = new ArrayList();
while (!c1.after(c2)) { // 循环对比,直到相等,n 就是所要的结果
//list.add(df.format(c1.getTime())); // 这里可以把间隔的日期存到数组中 打印出来
n++;
if(stype==1){
c1.add(Calendar.MONTH, 1); // 比较月份,月份+1
}
else{
c1.add(Calendar.DATE, 1); // 比较天数,日期+1
}
}
n = n-1;
if(stype==2){
n = (int)n/365;
}
System.out.println(startDay+" -- "+endDay+" 相差多少"+u[stype]+":"+n);
return n;
}
/**
* 向前或者向后推几个月
*
* @param date
* @param month
* @return
*/
public static Date timeToBeforeOrAfter(String strDate, String formatDate,
int num) {
try {
Calendar c = new GregorianCalendar();
Date d = str2Date(strDate, "yyyy-MM-dd");
c.setTime(d);
c.add(Calendar.MONTH, num);
SimpleDateFormat sdf = new SimpleDateFormat(formatDate);
return str2Date(sdf.format(c.getTime()), formatDate);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
/**
* 得到两日期相差几个月
*
* @param String
* @return
*/
public static long getMonthDiff(String startDate, String endDate)
throws ParseException {
long monthday;
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
Date startDate1 = fmt.parse(startDate);
Calendar starCal = Calendar.getInstance();
starCal.setTime(startDate1);
int sYear = starCal.get(Calendar.YEAR);
int sMonth = starCal.get(Calendar.MONTH);
int sDay = starCal.get(Calendar.DAY_OF_MONTH);
Date endDate1 = fmt.parse(endDate);
Calendar endCal = Calendar.getInstance();
endCal.setTime(endDate1);
int eYear = endCal.get(Calendar.YEAR);
int eMonth = endCal.get(Calendar.MONTH);
int eDay = endCal.get(Calendar.DAY_OF_MONTH);
monthday = ((eYear - sYear) * 12 + (eMonth - sMonth));
// 这里计算零头的情况,根据实际确定是否要加1 还是要减1
if (sDay < eDay) {
monthday = monthday + 1;
}
return monthday;
}
/**
* 奖string类型的日期转换为指定格式
*/
public static Date stringToDate(String dateStr) {
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_GENERAL1);
Date ddd = null;
try {
ddd = formatter.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
return ddd;
}
/**
* 奖date类型的日期转换为指定格式
*/
public static String dateToString(Date date) {
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_GENERAL1);
String ddd = null;
ddd = formatter.format(date);
return ddd;
}
public static String dateToString(Date date, String format) {
SimpleDateFormat formatter = new SimpleDateFormat(format);
String ddd = null;
ddd = formatter.format(date);
return ddd;
}
/**
* 将string类型的日期转换为指定格式:返回格式1的日期
* 错误将返回当前时间
*/
public static Date stringToDate1(String dateStr) {
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_GENERAL);
Date ddd = new Date();
try {
ddd = formatter.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
return ddd;
}
/**
*
* 获得当前时间加上或者减去几天的时间的字符串
*
* @param curr
* @param count
* @return
*/
public static String getAddDateStr(String dateStr, int addDate) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(stringToDate(dateStr));
calendar.add(Calendar.DATE, addDate);
return dateToString(calendar.getTime());
}
/**
*
* 获得当前时间加上或者减去几天的时间的字符串
*
* @param curr
* @param count
* @return
*/
public static String getAddDateStr(Date date, int addDate) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DATE, addDate);
return dateToString(calendar.getTime());
}
public static Date getAddDate(Date date, int addType, int addDate) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(addType, addDate);
return calendar.getTime();
}
public static String formatDate(Date date, String format) {
SimpleDateFormat formatter = new SimpleDateFormat(format);
return formatter.format(date);
}
public static Date parseDate(String dateStr, String format) throws ParseException {
SimpleDateFormat formatter = new SimpleDateFormat(format);
return formatter.parse(dateStr);
}
public static Date parseDate(Date date, String format) throws ParseException {
SimpleDateFormat formatter = new SimpleDateFormat(format);
return formatter.parse(formatter.format(date));
}
/**
* 定位到早上8点
*/
public static Date goToEighth(Date date){
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
}
/**
* 定位到0点
*/
public static Date goToZero(Date date){
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
}
/**
* @param d1 被减时间
* @param d2 减时间
* @return 两个时间相差的天数(忽略小时分钟秒)
*/
public static int getDaysDiffer(Date d1, Date d2){
double millisPerDay = DateUtils.MILLIS_PER_DAY;
return (int) (d2.getTime()/millisPerDay-d1.getTime()/millisPerDay);
}
public static long getMinuteDIffer(String d1,String d2){
try {
DateFormat df_parseDate = new SimpleDateFormat(FORMAT_FLIGHT_PLAN);
Date date1;
date1 = (Date) df_parseDate.parse(d1);
Date date2= (Date) df_parseDate.parse(d2);
return (date1.getTime()-date2.getTime())/(1000*60);//得到分钟数
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
/**
* @param d1
* @return 返回日期是星期几
*/
public static int getDateWeek(Date d1){
Calendar calendar = Calendar.getInstance();
calendar.setTime(d1);
int i = calendar.get(Calendar.DAY_OF_WEEK);
if(i == 1){
return 8;
}
return i;
}
public static void main(String[] args) throws ParseException {
// System.out.println(parseDate("2015-08-28 14:10", FORMAT_GENERAL4));
// System.out.println(getDateWeek(parseDate("2015-09-28", FORMAT_GENERAL1)));
// System.out.println(getDateWeek(new Date()));
Calendar c = Calendar.getInstance();
c.add(Calendar.DATE, 0);
System.out.println(getDaysDiffer(goToZero(new Date()), goToZero(c.getTime())));
}
}
ParamsUtil.java
import java.util.Map;
import org.apache.commons.lang.StringUtils;
public class ParamsUtil {
public static String nullDeal(Map params,String key,String defaultValue){
if(params == null || params.get(key)==null || "".equals(params.get(key))){
return StringUtils.isNotBlank(defaultValue) ? defaultValue : "";
}
return String.valueOf(params.get(key));
}
}
TimeFormatUtil.java
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TimeFormatUtil {
public static String getInterval(Date createAt) {
// 定义最终返回的结果字符串。
String interval = null;
long millisecond = new Date().getTime() - createAt.getTime();
long second = millisecond / 1000;
if (second <= 0) {
second = 0;
}
//*--------------微博体(标准)
if (second == 0) {
interval = "刚刚";
} else if (second < 30) {
interval = second + "秒以前";
} else if (second >= 30 && second < 60) {
interval = "半分钟前";
} else if (second >= 60 && second < 60 * 60) {//大于1分钟 小于1小时
long minute = second / 60;
interval = minute + "分钟前";
} else if (second >= 60 * 60 && second < 60 * 60 * 24) {//大于1小时 小于24小时
long hour = (second / 60) / 60;
if (hour <= 3) {
interval = hour + "小时前";
} else {
interval = "今天" + getFormatTime(createAt, "HH:mm");
}
} else if (second >= 60 * 60 * 24 && second <= 60 * 60 * 24 * 2) {//大于1D 小于2D
interval = "昨天" + getFormatTime(createAt, "HH:mm");
} else if (second >= 60 * 60 * 24 * 2 && second <= 60 * 60 * 24 * 7) {//大于2D小时 小于 7天
long day = ((second / 60) / 60) / 24;
interval = day + "天前";
} else if ( second <= 60 * 60 * 24 * 365 && second >= 60 * 60 * 24 * 7) {//大于7天小于365天
interval = getFormatTime(createAt, "MM-dd HH:mm");
} else if (second >= 60 * 60 * 24 * 365) {//大于365天
interval = getFormatTime(createAt, "yyyy-MM-dd HH:mm");
} else {
interval = "0";
}
return interval;
}
public static String getFormatTime(Date date, String Sdf) {
return (new SimpleDateFormat(Sdf)).format(date);
}
public static void main(String[] args) {
try {
System.out.println(getInterval(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2017-05-15 12:12:12")));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
数据库业务操作类
继承BaseDaoImpl 可调用增删改查的方法
UserInfoServiceImpl.java
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.zkkj.chat.dao.base.BaseDaoImpl;
import com.zkkj.chat.service.IUserService;
public class UserServiceImpl extends BaseDaoImpl implements IUserService {
@Override
public List<Map> getUserList(Map params) throws Exception {
// TODO Auto-generated method stub
return selectList("userInfo.getUserList",params);
}
@Override
public Map getUserById(Map params) throws Exception {
// TODO Auto-generated method stub
return (Map) selectOneByParam("userInfo.selectUserById", params);
}
@Override
public int updateUser(Map params) throws Exception {
// TODO Auto-generated method stub
return updateByParam("userInfo.updateUser", params);
}
@Override
public int addUser(Map params) throws Exception {
// TODO Auto-generated method stub
int count =0;
count =insert("userInfo.addUser", params);
return count;
}
}