基于Springboot和WebScoket寫的一個(gè)在線聊天小程序
(好幾天沒有寫東西了盔夜,也沒有去練手了怎燥,就看了看這個(gè)瘫筐。。铐姚。)
6
項(xiàng)目說明
- 此項(xiàng)目為一個(gè)聊天的小demo策肝,采用springboot+websocket+vue開發(fā)肛捍。
- 其中有一個(gè)接口為添加好友接口,添加好友會(huì)判斷是否已經(jīng)是好友之众。
- 聊天的時(shí)候:A給B發(fā)送消息如果B的聊天窗口不是A拙毫,則B處會(huì)提醒A發(fā)來一條消息。
- 聊天內(nèi)容的輸入框采用layui的富文本編輯器棺禾,目前不支持回車發(fā)送內(nèi)容缀蹄。
- 聊天可以發(fā)送圖片,圖片默認(rèn)存儲(chǔ)在D:/chat/目錄下膘婶。
- 點(diǎn)擊聊天內(nèi)容中的圖片會(huì)彈出預(yù)覽缺前,這個(gè)預(yù)覽彈出此條消息中的所有圖片。
- 在發(fā)送語(yǔ)音的時(shí)候悬襟,語(yǔ)音默認(rèn)發(fā)送給當(dāng)前聊天窗口的用戶衅码,所以錄制語(yǔ)音的時(shí)候務(wù)必保證當(dāng)前聊天窗口有選擇的用戶。
- 知道用戶的賬號(hào)可以添加好友脊岳,目前是如果賬號(hào)存在逝段,可以直接添加成功
老規(guī)矩,還是先看看小項(xiàng)目的目錄結(jié)構(gòu):
1
一割捅、先引入pom文件
這里就只放了一點(diǎn)點(diǎn)代碼(代碼太長(zhǎng)了)
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
二奶躯、創(chuàng)建對(duì)應(yīng)的yml配置文件
spring:
profiles:
active: prod
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/chat?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=UTC
driver-class-name: com.mysql.jdbc.Driver
#指定數(shù)據(jù)源
type: com.alibaba.druid.pool.DruidDataSource
# 數(shù)據(jù)源其他配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置監(jiān)控統(tǒng)計(jì)攔截的filters,去掉后監(jiān)控界面sql無法統(tǒng)計(jì)亿驾,'wall'用于防火墻
filters: stat,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
thymeleaf:
suffix: .html
prefix:
classpath: /templates/
cache: false
jackson: #返回的日期字段的格式
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
serialization:
write-dates-as-timestamps: false # true 使用時(shí)間戳顯示時(shí)間
http:
multipart:
max-file-size: 1000Mb
max-request-size: 1000Mb
#配置文件式開發(fā)
mybatis:
#全局配置文件的位置
config-location: classpath:mybatis/mybatis-config.xml
#所有sql映射配置文件的位置
mapper-locations: classpath:mybatis/mapper/**/*.xml
server:
session:
timeout: 7200
三嘹黔、創(chuàng)建實(shí)體類
這里就不再多說了,有Login,Userinfo,ChatMsg,ChatFriends
2
四颊乘、創(chuàng)建對(duì)應(yīng)的mapper(即dao層)還有對(duì)應(yīng)的mapper映射文件
(這里就舉出了一個(gè)参淹,不再多說)
public interface ChatFriendsMapper {
//查詢所有的好友
List<ChatFriends> LookUserAllFriends(String userid);
//插入好友
void InsertUserFriend(ChatFriends chatFriends);
//判斷是否加好友
Integer JustTwoUserIsFriend(ChatFriends chatFriends);
//查詢用戶的信息
Userinfo LkUserinfoByUserid(String userid);
}
<?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="com.chat.mapper.ChatFriendsMapper">
<select id="LookUserAllFriends" resultType="com.chat.bean.ChatFriends" parameterType="java.lang.String">
select userid,nickname,uimg from userinfo where userid in (select a.fuserid from chat_friends a where a.userid=#{userid})
</select>
<insert id="InsertUserFriend" parameterType="com.chat.bean.ChatFriends">
insert into chat_friends (userid, fuserid) value (#{userid},#{fuserid})
</insert>
<select id="JustTwoUserIsFriend" parameterType="com.chat.bean.ChatFriends" resultType="java.lang.Integer">
select id from chat_friends where userid=#{userid} and fuserid=#{fuserid}
</select>
<select id="LkUserinfoByUserid" parameterType="java.lang.String" resultType="com.chat.bean.Userinfo">
select * from userinfo where userid=#{userid}
</select>
</mapper>
五、創(chuàng)建對(duì)應(yīng)的業(yè)務(wù)類(即service)
(同樣的業(yè)務(wù)層這里也就指出一個(gè))
@Service
public class ChatFriendsService {
@Autowired
ChatFriendsMapper chatFriendsMapper;
public List<ChatFriends> LookUserAllFriends(String userid){
return chatFriendsMapper.LookUserAllFriends(userid);
}
public void InsertUserFriend(ChatFriends chatFriends){
chatFriendsMapper.InsertUserFriend(chatFriends);
}
public Integer JustTwoUserIsFriend(ChatFriends chatFriends){
return chatFriendsMapper.JustTwoUserIsFriend(chatFriends);
}
public Userinfo LkUserinfoByUserid(String userid){
return chatFriendsMapper.LkUserinfoByUserid(userid);
}
}
六乏悄、創(chuàng)建對(duì)應(yīng)的控制器
這里再說說項(xiàng)目的接口
- /chat/upimg
聊天圖片上傳接口 - /chat/lkuser
這個(gè)接口用來添加好友的時(shí)候:查詢用戶浙值,如果用戶存在返回用戶信息,如果不存在返回不存在 - /chat/adduser/
這個(gè)接口是添加好友接口檩小,會(huì)判斷添加的好友是否是自己开呐,如果添加的好友已經(jīng)存在則直接返回 - /chat/ct
跳轉(zhuǎn)到聊天界面 - /chat/lkfriends
查詢用戶的好友 - /chat/lkuschatmsg/
這個(gè)接口是查詢兩個(gè)用戶之間的聊天信息的接口,傳入用戶的userid规求,查詢當(dāng)前登錄用戶和該用戶的聊天記錄筐付。 - /chat/audio
這個(gè)接口是Ajax上傳web界面js錄制的音頻數(shù)據(jù)用的接口
(同樣就只寫一個(gè))
@Controller
public class LoginCtrl {
@Autowired
LoginService loginService;
@GetMapping("/")
public String tologin(){
return "user/login";
}
/**
* 登陸
* */
@PostMapping("/justlogin")
@ResponseBody
public R login(@RequestBody Login login, HttpSession session){
login.setPassword(Md5Util.StringInMd5(login.getPassword()));
String userid = loginService.justLogin(login);
if(userid==null){
return R.error().message("賬號(hào)或者密碼錯(cuò)誤");
}
session.setAttribute("userid",userid);
return R.ok().message("登錄成功");
}
}
七、創(chuàng)建對(duì)應(yīng)的工具類以及自定義異常類
- 表情過濾工具類
public class EmojiFilter {
private static boolean isEmojiCharacter(char codePoint) {
return (codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA)
|| (codePoint == 0xD)
|| ((codePoint >= 0x20) && (codePoint <= 0xD7FF))
|| ((codePoint >= 0xE000) && (codePoint <= 0xFFFD))
|| ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
}
@Test
public void testA(){
String s = EmojiFilter.filterEmoji("您好??阻肿,你好啊");
System.out.println(s);
}
- Md5數(shù)據(jù)加密類
static String[] chars = {"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
/**
* 將普通字符串用md5加密瓦戚,并轉(zhuǎn)化為16進(jìn)制字符串
* @param str
* @return
*/
public static String StringInMd5(String str) {
// 消息簽名(摘要)
MessageDigest md5 = null;
try {
// 參數(shù)代表的是算法名稱
md5 = MessageDigest.getInstance("md5");
byte[] result = md5.digest(str.getBytes());
StringBuilder sb = new StringBuilder(32);
// 將結(jié)果轉(zhuǎn)為16進(jìn)制字符 0~9 A~F
for (int i = 0; i < result.length; i++) {
// 一個(gè)字節(jié)對(duì)應(yīng)兩個(gè)字符
byte x = result[i];
// 取得高位
int h = 0x0f & (x >>> 4);
// 取得低位
int l = 0x0f & x;
sb.append(chars[h]).append(chars[l]);
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
- 測(cè)試數(shù)據(jù)加密類
public class TestUtil {
@Test
public void testA(){
String s = Md5Util.StringInMd5("123456");
System.out.println(s);
}
}
八、引入對(duì)應(yīng)的靜態(tài)資源文件(這個(gè)應(yīng)該一開始就做的)
4
九丛塌、自定義一些配置并且注入到容器里面
- Druid數(shù)據(jù)源
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid(){
return new DruidDataSource();
}
//配置Druid的監(jiān)控
//1.配置要給管理后臺(tái)的Servlet
@Bean
public ServletRegistrationBean servletRegistrationBean(){
ServletRegistrationBean bean=new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
Map<String,String> initParams=new HashMap<>();
initParams.put("loginUsername","admin");
initParams.put("loginPassword","admin233215");
initParams.put("allow","");//默認(rèn)允許ip訪問
initParams.put("deny","");
bean.setInitParameters(initParams);
return bean;
}
//2.配置一個(gè)監(jiān)控的filter
@Bean
public FilterRegistrationBean webStarFilter(){
FilterRegistrationBean bean=new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
Map<String,String> initParams=new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");
bean.setInitParameters(initParams);
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
}
- 靜態(tài)資源以及攔截器
@Configuration
public class MyConfig extends WebMvcConfigurerAdapter {
//配置一個(gè)靜態(tài)文件的路徑 否則css和js無法使用较解,雖然默認(rèn)的靜態(tài)資源是放在static下畜疾,但是沒有配置里面的文件夾
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
@Bean
public WebMvcConfigurerAdapter WebMvcConfigurerAdapter() {
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//registry.addResourceHandler("/pic/**").addResourceLocations("file:D:/chat/");
registry.addResourceHandler("/pic/**").addResourceLocations("file:D:/idea_project/SpringBoot/Project/Complete&&Finish/chat/chatmsg/");
super.addResourceHandlers(registry);
}
};
return adapter;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注冊(cè)TestInterceptor攔截器
InterceptorRegistration registration = registry.addInterceptor(new AdminInterceptor());
registration.addPathPatterns("/chat/*");
}
}
- WebSocketConfigScokt通信配置
@Configuration
@EnableWebSocket
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
十、進(jìn)行測(cè)試
這是兩個(gè)不同的用戶
7
8
當(dāng)然了印衔,還可以進(jìn)行語(yǔ)音啡捶,添加好友
今天的就寫到這里吧!謝謝奸焙!
這里要提一下我的一個(gè)學(xué)長(zhǎng)的個(gè)人博客瞎暑,當(dāng)然了,還有我的与帆,謝謝
理木客
我的