javaweb:在线聊天网站(框架版)

news/2024/5/11 2:10:46/文章来源:https://blog.csdn.net/name_z/article/details/55189873

之前写过一次在线聊天网站,不过那次是无框架版的,这次用框架构建网站,基本功能和上次差不多

涉及知识

java
spring(4.3.5):spring、spring MVC
hibernate
bootstrap
jsp
JavaScript,jquery
websocket
mysql

功能

1.用户的登录、注册、注销、密码修改
2.获知在线用户名字及数量
3.向在线用户发送消息
4.查看与该用户的历史信息
5.当有非当前聊天用户的信息到来时,会有提示

数据库

类一览

数据库类

mysql数据库建立

一个账户表,一个聊天内容表

create database db_talk;
create table tbl_account
(id int not null primary key auto_increment,name varchar(30) not null unique,password char(20) not null
)CHARACTER SET 'utf8'
COLLATE 'utf8_general_ci';create table tbl_talk
(id int not null primary key auto_increment,content varchar(255),srcAccountId int not null,targetAccountId int not null,time datetime not null default now(),foreign key(srcAccountId) references tbl_account(id),foreign key(targetAccountId) references tbl_account(id)
)CHARACTER SET 'utf8'
COLLATE 'utf8_general_ci';

hibernate实体层bean

P.S.关于hibernate注解解释可看http://blog.csdn.net/name_z/article/details/51318271
实体类Account和TalkContent都继承了通用实体类CommonBean

CommonBean

@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class CommonBean {@Id@Column(name = "id", insertable = false, updatable = false)@GeneratedValue(strategy = GenerationType.IDENTITY)protected int id;@Transientprotected static final String DEFAULT_ID_COLUMN_NAME = "id";public int getId() {return id;}
//    public void setId(int id) {
//        this.id = id;
//    }//获取本类的简单类名public abstract String getClassSimpleName();public String getIdColumnName(){return DEFAULT_ID_COLUMN_NAME;}
}@Entity
@Table(name = "tbl_talk")
public class TalkContent extends CommonBean {...}@Entity
@Table(name = "tbl_account")
public class Account extends CommonBean {...}

使用CommonBean原因

1.各实体类的相同部分(如这次的id)可放在CommonBean中,从而减少了代码量,使代码整洁
2.采用abstract方法约束子对象,方便后面dao层使通用持久层CommonDao类

hibernate持久层dao

使用模板与反射减少代码量。
所有dao类接口都继承了ICommonDao,CommonDao实现了ICommonDao,所有dao类实现都继承了CommonDao
CommonDao使用模板设计,所有子类能不做修改直接调用CommonDao中方法进行实体的增删改查

接口

public interface ICommonDao<T extends CommonBean> {boolean save(T entity);boolean delete(T entity);boolean updateByID(T entity);T getByID(T entity);T getByID(int id);List<T> getAll();void setSessionFactory(SessionFactory sessionFactory);
}public interface IAccountDao extends ICommonDao<Account> {Account getByName(String name);Account getByName(Account account);
}public interface ITalkContentDao extends ICommonDao<TalkContent> {...}

CommonBean

通过继承实现CommonBean类后,对于增删改查的方法均可不作修改直接调用父类CommonBean的增删改查即可对子类进行操作

@Repository
public abstract class CommonDao<T extends CommonBean> implements ICommonDao<T> {@Autowiredprotected SessionFactory sessionFactory;private static final String SAVE_METHOD = "save";private static final String DELETE_METHOD = "delete";private static final String UPDATE_METHOD = "update";protected final String CLASS_SIMPLENAME;protected final String ID_COLUMN_NAME;/*** 传入一个已经实体化的对象(非null对象),并用该对象初始化CLASS_SIMPLENAME、ID_COLUMN_NAME两个变量(CommonBean中有这两个方法)* * @param entity*/public CommonDao(T entity) {this.CLASS_SIMPLENAME = entity.getClassSimpleName();this.ID_COLUMN_NAME = entity.getIdColumnName();}/*** 获取开启事务后的session* * @return*/protected Session getCurrentSession() {Session session = this.sessionFactory.getCurrentSession();try {session.beginTransaction();} catch (TransactionException e) {}return session;}/*** 传入hql语句进行查询,返回list* * @param hql* @return*/@SuppressWarnings("unchecked")protected List<T> queryList(String hql) {Session session = this.getCurrentSession();Query query = session.createQuery(hql);return query.list();}/*** 传入hql语句进行查询,如果查询不到结果,返回null* * @param hql* @return*/@SuppressWarnings("unchecked")protected T queryUnique(String hql) {Session session = this.getCurrentSession();Query query = session.createQuery(hql);return (T) query.uniqueResult();}@Overridepublic void setSessionFactory(SessionFactory sessionFactory) {this.sessionFactory = sessionFactory;}private Method getMethod(String operation) throws Exception {return Session.class.getMethod(operation, Object.class);}/*** 通过反射执行执行增、删、改操作* * @param oper* @param entity* @return*/private boolean execute(String oper, T entity) {try {Session session = this.getCurrentSession();Method method = this.getMethod(oper);method.invoke(session, entity);session.getTransaction().commit();return true;} catch (Exception e) {e.printStackTrace();return false;}}@Overridepublic boolean save(T entity) {return this.execute(SAVE_METHOD, entity);}@Overridepublic boolean delete(T entity) {return this.execute(DELETE_METHOD, entity);}@Overridepublic boolean updateByID(T entity) {return this.execute(UPDATE_METHOD, entity);}@Overridepublic T getByID(T entity) {return this.getByID(entity.getId());}@Overridepublic T getByID(int id) {return this.queryUnique(HQLGenerator.generateSingleEqualQueryHql(this.CLASS_SIMPLENAME,this.ID_COLUMN_NAME, String.valueOf(id)));}@SuppressWarnings("unchecked")@Overridepublic List<T> getAll() {Session session = this.getCurrentSession();return session.createQuery(HQLGenerator.generateAllQuery(this.CLASS_SIMPLENAME)).list();}

AccountDao类:

@Repository
public class AccountDao extends CommonDao<Account> implements IAccountDao {private static final String NAME_PROP_NAME = "name";public AccountDao() {super(new Account());}@Overridepublic Account getByName(String name) {return this.queryUnique(HQLGenerator.generateSingleEqualQueryHql(this.CLASS_SIMPLENAME, NAME_PROP_NAME, name));}@Overridepublic Account getByName(Account account) {return this.getByName(account.getName());}}

hql语句生成

hql语句的获取统一从一个类中获取,负责的hql语句直接写成static final变量

    public class HQLGenerator {//from classname obj where obj.column = 'value'private static final String SINGLE_QUERY = ALL_QUERY + " obj where obj." + COLUMN_PLACER + BLANK + EQUAL + BLANK + SINGLE_QUOTE + VALUE_PLACER + SINGLE_QUOTE;.../*** 生成对单个列的值进行查询的hql语句* * @param classname*            类名* @param column*            列名* @param value*            值* @return*/public static String generateSingleEqualQueryHql(String classname, String column, String value) {return SINGLE_QUERY.replace(CLASSNAME_PLACER, classname).replace(COLUMN_PLACER, column).replace(VALUE_PLACER,value);}...
}

网页交互

类一览:

网页交互
AccountManager:负责账户的登录、修改
OnlineAccountManager:保存当前在线账户的名字与session联系
TalkManager:负责聊天内容的保存,分为保存到内存和保存到数据库

TalkManager

可以指定保存在内存中的聊天内容的最大数量,超过清空

保存到内存中的聊天内容

每次点开目标对象,都会显示这些内容(服务器中途没有关闭过)

保存到数据库中的内容

只保存在数据库中,没有保存在内存中的内容,只有点击历史信息后,才能显示,点击历史信息后,这部分内容也会保存到内存中

spring mvc表单提交

就是点击按钮后,客户端才能发送数据给服务器,服务器spring mvc返回视图以及数据

登录页面jsp:

<form:form method="POST"  modelAttribute="account"  action="/Talk/login.do"><table><tr><td><form:label path="name" >名字:</form:label></td><td><form:input path="name" id="name" class="form-control input-sm"/></td></tr><tr><td><form:label path="password">密码:</form:label></td><td><form:password path="password" id="password" class="form-control input-sm"/></td></tr><tr><td colspan="2"><input type="submit" value="登录" /></td></tr></table>
</form:form>

login的controller:

@Controller
public class LoginController {@RequestMapping(method = RequestMethod.POST, path = "/login")public String login(ModelMap model, Account account) {account = AccountManager.login(account);if (account != null) {TalkContent talkContent = new TalkContent();talkContent.setSrcAccount(account);talkContent.setTargetAccountName("");//给视图添加数据model.addAttribute("talkContent", talkContent);model.addAttribute("onlineNum", OnlineAccountManager.getOnlineNum());model.addAttribute("accounts", OnlineAccountManager.getOnlineAccountsName());return "main";}model.addAttribute("warnMessage", AccountManager.ERROR_LOGIN);return "login";}@RequestMapping(method = RequestMethod.GET, path = "/login")public String getLoginJsp(ModelMap model) {//因为jsp页面提交中注明account,因此必须添加account属性model.addAttribute("account", new Account());model.addAttribute("warnMessage", "");return "login";}
}

使用websocket和jquery完成实时数据显示

因为客户端与客户端之间的交互需要实时性(发送的、接收到的信息能马上显示),因此不能用spring mvc表单提交,要用websocket。而使用websocket提交信息后,服务器只会发回信息,而不是网页,因此需要jquery实时更新当前显示的信息,包括聊天信息和提示信息

步骤:

1.客户端与服务器建立联系后,客户端马上向服务器发送注册信息(将账户名字与(websocket)session构成联系),每次的刷新都回导致注册信息的更新
2.用户点击发送按钮后,客户端向服务器发送信息,服务器保存信息并且发送给目标用户
3.用户关闭页面时,服务器获知并且在注册信息表中删除该用户

main.jsp

注意点:
聊天内容和提示信息除了有id方便jquery的操作,还需要${}保证当点击刷新或者其他spring mvc提交表单的操作后,聊天内容和提示信息可以从服务器中获取而显示,否则,只有jquery设置的内容会丢失。

...
<!-- 聊天内容部分 -->
<div class="panel-body" data-spy="scroll" data-target="#navbar-example" data-offset="300" style="height: 300px; overflow: auto; position: relative;"><pre id="talks">${talks}</pre>
</div>
...
<!-- 信息提示部分 -->
<div class="panel-body" data-spy="scroll" data-target="#navbar-example" data-offset="0" style="height: 250px; overflow: auto; position: relative;"><pre id="message">${message}</pre>
</div>
...
<!-- 发送聊天内容部分 -->
<div class="input-group"><input id="talk" type="text" class="form-control"> <span class="input-group-addon"> <button id="send" type="button" class="btn btn-default">发送</button></span>
</div>
...

main.js

//发送聊天内容,格式为:from(发送人)to(接收人)talk(聊天内容)
function setBtnSend() {$(document).ready(function() {$("#send").click(function() {var srcName = $("#accountName").text();var targetName = $("#targetAccountName").text();var talk = $("#talk").val();var message = "from(" + srcName + ")to(" + targetName + ")talk(" + talk + ")";sendMessage(message);var temp = $("#talks").text();$("#talks").text(temp + "\n" + srcName + ">" + talk);});});}function setWebSocket() {//当与服务器建立联系后,马上发送注册信息,因此每次页面的刷新也会重新发送注册信息webSocket.onopen = function(event) {var message = "regist(" + $("#accountName").text() + ")";sendMessage(message);};...//接受到服务器发送的信息webSocket.onmessage = function(event) {var targetName = $("#targetAccountName").text();var temp = $("#talks").text();var message = event.data;//判断发送对象是否为当前聊天对象,是则显示到聊天内容,否则显示到提示信息中if (message.indexOf(targetName + ">") > 0) {$("#talks").text(temp + "\n" + message);} else {$("#message").text(message);}}
}

服务器负责接受websocket的controller

@Controller
@ServerEndpoint("/talk")
public class TalkWebSocket extends TextWebSocketHandler {.../*** 接受客户端发送的信息,如果为注册信息则注册(将用户名字与该session建立联系),否则为聊天信息,如果为有效聊天信息则保存到数据库,并且发送给目标账户* @param message* @param session* @throws IOException*/@OnMessagepublic void onMessage(String message, Session session) throws IOException {message = URLDecoder.decode(message, "UTF-8");if(message.startsWith(REGIST)){//注册该用户,将名字与session构成联系OnlineAccountManager.regist(regexGroupOne(REGIST_PATTERN, message), session);}else{String srcAccountName = regexGroupOne(SRCACCOUNT_PATTERN, message);String targetAccountName = regexGroupOne(TARGETACCOUNT_PATTERN, message);String talk = regexGroupOne(TALK_PATTERN, message);//如果接收人为空或者聊天内容为空,直接忽略该条信息if(targetAccountName == null || "".equals(talk)){return ;}//根据名字获取sessionSession targetSession = OnlineAccountManager.getSession(targetAccountName);if(targetSession != null){//保存聊天内容到数据库TalkManager.saveTalkInDatabase(srcAccountName, targetAccountName, talk);//使用session向客户端发送信息targetSession.getBasicRemote().sendText(srcAccountName + ">" + talk);}}}
}

bootstrap

采用网格系统作为基础构建网页,使用部分bootstrap中的部件:导航栏、输入狂组、按钮、面板

效果展示

登录页面

http://localhost:8080/Talk/login.do
login
登录失败:
login-error

注册页面

http://localhost:8080/Talk/regist.do
regist
登录失败:
regist-error

主页:

刚登录进来的页面:
main
main-1
发送消息:
send
接受信息但当前聊天内容并不是该发送者:
recieve
接受信息:
recieve2

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

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

相关文章

利用TortoiseGit(小乌龟)将项目上传至GitHub网站

2019独角兽企业重金招聘Python工程师标准>>> 准备 1.拥有一个GitHub账户2.安装了TortoiseGit&#xff08;小乌龟&#xff09;具体过程 一、在GitHub上建立新的仓库 起好仓库名&#xff0c;填好描述&#xff0c;在Add .gitgnore中选择Java&#xff08;根据你自己需求…

一些缩短树莓派学习曲线的书籍、课程和网站

2019独角兽企业重金招聘Python工程师标准>>> 树莓派是一款小型单板计算机&#xff0c;最初用于教学和学习编程和计算机科学。但如今它有更多用处。它是一种经济的低功耗计算机&#xff0c;人们将它用于各种各样的事情 —— 从家庭娱乐到服务器应用&#xff0c;再到物…

大型分布式网站架构实战项目分析

2019独角兽企业重金招聘Python工程师标准>>> 大型分布式网站架构实战项目分析 转载于:https://my.oschina.net/u/1168056/blog/1802675

zblog mysql数据库无法连接_ZBlog博客网站错误:MySQL数据库无法连接

前言前天搭建的博客网站&#xff0c;睡醒一觉起来网站挂逼了&#xff0c;其间无任何操作。主页都进不去&#xff0c;提示“MySQL数据库无法连接”&#xff0c;无论怎么刷新重启服务器都没用。最终从中午1点搞到凌晨2点&#xff0c;皇天不负有心人终于解决了。其实问题很简单&am…

.net core Asp.net Mvc Ef 网站搭建 vs2017 1)

1&#xff09;开发环境搭建 首先下载安装vs2017 地址 &#xff1a;https://www.visualstudio.com/zh-hans/downloads/ 安装勾选几项如下图 ,注意点在单个组件时.net core 运行时一定要勾上,很多人都没勾结果新增不了.net core 项目 2&#xff09;开发 1.新增.net core mvc …

LAMP架构部署和动态网站环境的配置

实验环境&#xff1a;操作系统&#xff1a;centos 7.5服务器IP&#xff1a;192.168.10.5运行用户&#xff1a;root连接工具&#xff1a;xshell工具web环境&#xff1a;Linuxapachephpmariadb&#xff08;LAMP架构&#xff09;大型动态应用系统平台主要是针对于大流量、高并发网…

我的博客网站开发5——博文正文页

为实现页面间的统一性和开发时代码的工作量&#xff0c;我们将页面相同的布局做成母版页&#xff0c;变化的内容在内容页进行变化。如下图&#xff1a; 这样&#xff0c;我们在写博文的显示全文页面时&#xff0c;我们只需在新增页面引用母版页就可实现&#xff0c;页面相同页面…

建立个人网站需要学习哪些知识?学习的顺序是什么?

首先&#xff0c;做个人的网站&#xff0c;不是写笔记那么肯定是为了我展示给别人看。 想要把自己写的网站展示给互联网&#xff0c;就要把代码部署到服务器&#xff0c;如果按照正常的流程&#xff0c;就要首先登陆百度云&#xff0c;阿里云什么的&#xff0c;购买服务器&…

Chrome 不想让 HTTPS 网站通过 HTTP 下载文件

开发四年只会写业务代码&#xff0c;分布式高并发都不会还做程序员&#xff1f; >>> 你是否经历过访问的明明是一个 HTTPS 网站&#xff0c;但是有时候站内下载东西使用的协议却是 HTTP&#xff0c;这其实存在安全隐患&#xff0c;现在 Chrome 不想让这样的事情发生…

Google也来凑热闹-网站导航

网站导航这个已经在国内做烂掉的东西&#xff0c;最近大鳄级别的Google也来凑热闹了&#xff0d;Google网站导航&#xff0c;据他们自己说&#xff1a; 在推这款产品之初&#xff0c;我们做了大量的调研&#xff0c;。。。我们发现还有大量的另一类用户&#xff0c;我们在帮助…

网站数据安全防护的八大要诀

不管是网络还是终端&#xff0c;信息安全问题始终是人们所最为关心的问题&#xff0c;所以当人们的数据中心正走向网络的时候&#xff0c;人们的安全防护也必须紧跟这个脚步。 1、认证和口令管理 这主要是一种一次性的活动而且仅仅是作为项目的一部分而完成的。有人可能会问一…

php网站防止sql注入攻击方法

网站安全防护—该如何防止SQL注入攻击&#xff1f; 移动互联网的发展势头已经远远超过PC互联网&#xff0c;手机移动端上网&#xff0c;以及持有量远超PC电脑&#xff0c; 随着移动大数据、区块链的技术在不断的完善&#xff0c;成熟&#xff0c;日常生活中经常会听到某某网站…

网站被黑 如何做好网站安全防护

网站被攻击&#xff0c;首先牵扯到的就是网站的开发语言&#xff0c;包括了代码语言&#xff0c;以及数据库语言&#xff0c;目前大多数网站都是使用的PHP&#xff0c;JAVA&#xff0c;.net语言开发&#xff0c;数据库使用的是mysql&#xff0c;oracle等数据库&#xff0c;那么…

网站被黑 怎么检测代码含有后门

收到阿里云的短信提醒说是网站存在后门&#xff0c;webshell恶意通信行为&#xff0c;紧急的安全情况&#xff0c;我第一时间登录阿里云查看详情&#xff0c;点开云盾动态感知&#xff0c;查看了网站木马的详细路径以及webshell的特征&#xff0c;网站从来没有出现过这种情况&a…

如何防止网站数据库被攻击被篡改?

某一网站平台的客户数据库被黑客篡改了&#xff0c;篡改了会员的卡信息以及金额&#xff0c;包括zhu单也被黑客篡改&#xff0c;导致平台的损失很大&#xff0c;在后台提现的时候&#xff0c;客户才发现会员的数据有异常&#xff0c;觉得不得劲&#xff0c;查询该会员账号的所有…

企业网站服务器遭到黑客入侵? 如何做好安全防护

好多企业网站遭遇黑客攻击&#xff0c;像黑客入侵在互联网只要有数据网络&#xff0c;就能使用数据网络远程操作目标的笔记本电脑、网络服务器、企业网站&#xff0c;从而任意地读取或篡改目标的重要数据&#xff0c;又又或者使用目标系统软件上的功能模块&#xff0c;比如对手…

如何防护黑客攻击网站漏洞?

从今年3月份全世界黑客攻击网站分析局势来看&#xff0c;黑客攻击的网站中中国占有了绝大多数。那麼作为一个公司或是开发公司&#xff0c;如何防止自身的网站黑客攻击&#xff0c;从企业网站建设之初&#xff0c;就应当搞好这种安全对策&#xff0c;当你的网站保证以下几个方面…

Linux中如何部署动态网站环境

当谈论起网站时&#xff0c;我们可能听说过静态和动态这两个词&#xff0c;但却不知道它们的含义&#xff0c;或者从字面意思了解一些却不知道它们的区别。 这一切可以追溯到网站和网络应用程序&#xff0c;Web应用程序是一个网站&#xff0c;但很多网站不是Web应用程序&#…

网站受攻击的具体形式是什么?怎么判断出网站被攻击?

现在做网站的站长面对网站攻击是在所难免的事&#xff0c;特别是一些比较热门的行业以及一些比较小的企业&#xff0c;更是被这些网站攻击整得焦头烂额。那么如果我们要解决攻击的问题&#xff0c;我们就必须去了解攻击到底是一个什么东西&#xff0c;具体的攻击有什么形式。 …