JavaWeb在线聊天系统开发
项目简介
使用前后端分离进行JavaWeb开发多用户在线聊天系统,前端由HTML5**、CSS、JavaScript开发,后端系统以Java语言开发。后端系统在本地开发完成后打包放在腾讯云端centOS服务器上不间断运行,可实现任何终端都可访问聊天系统。
具体要使用的技术还有Nginx、redis、第三方框架等。笔者这里通过服务器IP地址进行访问,有需要也可设置通过域名访问系统,欢迎讨论交流。
预览
前端实现
前端的编写主要实现注册页面index.html和聊天页面chat.html,注册页面对账号和密码输入内容进行限制,可通过代码进行自定义限制:
account:[
{required:true,message:'请输入账号!', trigger:'blur'},
{min:2,max:20,message:'账号信息不少于2个字符且不能超过20个字符', trigger:'blur'}
],
password:[
{required:true,message:'请输入密码!', trigger:'blur'},
{min:2,max:10,message:'账号信息不少于2个字符且不能超过10个字符', trigger:'blur'}
],
前端数据通过webSocket与服务器进行通信,因此首先得有自己的服务器,服务器可在腾讯云或阿里云进行注册,本系统采用系统8080端口,云服务器为centOS系统,。有了自己的服务器之后在下面的index.html登录页面中需要把ip换成自己的服务器ip地址:
//此ip地址需要修改为自己的服务器ip地址
axios.post("http://xx.xx.xx.xx:8080/api/index",this.user)
index.html
前端开发还使用到了element框架、vue框架,登陆页面index.html完整代码如下:
<!--
* @Author: liuy
* @Date: 2021-1-6 14:30:54
* @LastEditTime: 2021-01-06 14:30:29
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \web\index.html
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>QQ注册</title>
<!--在网页的页签上加入一个小icon图标-->
<link rel="shortcut icon" href="images/qq.ico" type="image/x-icon">
<!--引入register.css文件-->
<link rel="stylesheet" href="css/register.css">
<!--引入饿了么UI的CSS文件-->
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<!--img src="data:image/jpeg;base64,"-->
<!--div#left+tab-->
<div id="left"></div>
<!--表单注册区域的div容器-->
<div id="app">
<el-form :model="user" :rules="rules" ref="myform" label-width="100px" class="demo-ruleForm">
<el-form-item prop="account">
<el-input placeholder="请输入要注册的账号" v-model="user.account"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input placeholder="请输入要注册的密码" show-password v-model="user.password"></el-input>
</el-form-item>
<el-form-item style="text-align: center;">
<input id="faceFile" style="display:none" type="file" @change="showImg">
<el-image id="face" @click="showFile" :src="user.face">
</el-form-item>
<el-form-item>
<el-button @click="register" style="width: 384px" type="primary">立即注册</el-button>
</el-form-item>
</el-form>
</div>
<!--引入vue/ajax/饿了么框架-->
<script src="js/vue.js"></script>
<!--发送数据包-->
<script src="js/axios.min.js"></script>
<script src="js/index.js"></script>
<!--申明脚本区-->
<script>
var app = new Vue({
el: '#app', //vue框架作用域该app节点内
//数据区域,e1,data,methods是固定写法,内部的变量名和方法名
//可以随意取名
data: {
user:{
account: null,
password: null,
face: 'images/default_face.png'
},
rules:{
account:[
{required:true,message:'请输入账号!', trigger:'blur'},
{min:2,max:20,message:'账号信息不少于2个字符且不能超过20个字符', trigger:'blur'}
],
password:[
{required:true,message:'请输入密码!', trigger:'blur'},
{min:2,max:10,message:'账号信息不少于2个字符且不能超过10个字符', trigger:'blur'}
]
}
},
//方法区域
methods: {
register(){
this.$refs['myform'].validate((valid) => {
if (valid) {
//把要注册的数据发送给java后端
console.log(this.user);
console.log(this.user.account);
//alert('submit!');
//127.0.0.1此ip地址表示自己的地址,then表示请求成功后执行的方法
axios.post("http://xx.xx.xx.xx:8080/api/register",this.user)
.then(res => {
if(res.data.code == 200){
this.$message({
message:'注册成功!',
type:'success',
center:true,
showClose:true,
onClose:e =>{
//保存登陆人信息
sessionStorage.setItem("user",this.user.account);
//跳转到聊天窗口
location = 'chat.html';
}
});
}else{
this.$message.error({
message: res.data.message
});
}
//console.log(res);
})
}
});
},
showValue() {
alert(this.account);
},
showFile(){
document.querySelector("#faceFile").click();
},
showImg(e) {
//因为this只能在该方法中用,在子方法用不了,所以用这个变量临时保存
var vueThis = this;
//得到用户选择的文件
var v = e.target.files[0];
//把它转为base64编码
var reader = new FileReader();
//对变量v进行转码
reader.readAsDataURL(v);
//转码完成后,回去执行这个方法
reader.onload = function(r){
vueThis.user.face = r.target.result;
}
}
}
});
</script>
</body>
</html>
chat.html
聊天页面chat.html中也需要将ip地址换为自己服务器的ip地址:
else {
//这里需要把ip地址换为自己服务器的ip地址
var url = "ws://xx.xx.xx.xx:8080/chat?account=" + account;
this.ws = new WebSocket(url);
this.ws.onopen = this.doOpen;
this.ws.onmessage = this.doMessege;
}
聊天页面chat.html完整代码:
<!--
* @Author: liuy
* @Date: 2021-01-04 10:25:29
* @LastEditTime: 2021-01-08 09:46:52
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \web\chat.html
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chat WIndow</title>
<!--在网页的页签上加入一个小icon图标-->
<link rel="shortcut icon" href="images/bq.png" type="image/x-icon">
<!--引入register.css文件-->
<link rel="stylesheet" href="css/chat.css">
<!--引入饿了么UI的CSS文件-->
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<!--div整个网页-->
<div id="web_bg" style="background-image: url('assets/background.jpg');">
<div id="app">
<div id="main">
<div id="left">
<div id="records">
<div class = "message_line" v-for="r in messageRecords">
<div v-if="r.isMe == 0" class="r">
<div class="r_left">
<img :src="r.user.face" class="record_face">
</div>
<div class="r_right">
<div class="nickname">{{r.user.account}}</div>
<div class="message_bg">{{r.message}}</div>
</div>
</div>
<div v-if="r.isMe == 1" class="rr">
<div class="message_bg_me">{{r.message}}</div>
<div>
<img :src="r.user.face" class="record_face">
</div>
</div>
</div>
</div>
<div id="tools"></div>
<div id="contents">
<textarea @keydown.enter="sendMessage" v-model="message" id="contents_text"></textarea>
</div>
<div id="buttons">
<el-button>关闭</el-button>
<el-button @click="sendMessage" type="primary">发送</el-button>
</div>
</div>
<!--循环好友列表-->
<div id="right">
<div class="online" v-for="f in friends">
<img class="face" :src="f.face">
<span class="text1">{{f.account.substring(0,12)}}</span>
<span class="jianbian">{{f.account.substring(12)}}</span>
</div>
</div>
</div>
</div>
</div>
<!--引入vue/ajax/饿了么框架-->
<script src="js/vue.js"></script>
<!--发送数据包-->
<script src="js/axios.min.js"></script>
<script src="js/index.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
ws: null,
message: '',
//好友
friends: [],
messageRecords: [
//{ user: { account: 'admin', face: 'images/game.ico' }, message: 'hello', isMe: 1 },
//{ user: { account: 'bigpig', face: 'images/default_face.png' }, message: 'nice', isMe: 0 }
]
},
methods: {
doOpen() {
this.$notify({
title: '最新消息',
message: 'can you see me?',
position: 'bottom-right',
//type: 'info'
})
},
sendMessage() {
//判断是否输入空格
if(this.message.trim()){
//发送给后端
this.ws.send(this.message);
}
//发送完数据,清空输入框
this.message = '';
//给予输入框焦点光标
document.getElementById("contents_text").focus();
//alert(this.message);
},
doMessege(res) {
var responseEntity = JSON.parse(res.data);
//10代表好友列表
if (responseEntity.code == 10) {
//更新好友列表
this.refreshOnlineUser(responseEntity.data);
}
//20代表好友消息
if (responseEntity.code == 20) {
//更新聊天消息
this.refreshMessage(responseEntity.data, responseEntity.message);
}
//网页后台输出用户账号 console.log(res.data);
},
refreshOnlineUser(data) {
this.friends = data;
},
refreshMessage(user, message) {
//判断是否是自己发的消息
var isMe = (user.account == sessionStorage.getItem('user') ? 1 : 0);
this.messageRecords.push({ 'user': user, 'message': message,'isMe' : isMe});
//让多页消息时总是显示最新消息
this.$nextTick(() =>{
document.querySelector('#records').scrollTop = document.querySelector('#records').scrollHeight;
});
}
},
//页面挂载的时候会默认执行的方法
mounted() {
var account = sessionStorage.getItem("user");
//如果用户没有登录
if (!account) {
this.$message({
showClose: true,
message: '您还没有登录,请先登录ovo',
type: 'error',
center: true,
showClose: true,
onClose: function () {
location = 'index.html';
}
});
//alert('请先登录');
location = 'login.html';
} else {
var url = "ws://xx.xx.xx.xx:8080/chat?account=" + account;
this.ws = new WebSocket(url);
this.ws.onopen = this.doOpen;
//alert(1);
this.ws.onmessage = this.doMessege;
}
}
})
</script>
</body>
</html>
chat.css
完整代码如下:
@charset "utf-8";
#main{
margin:auto;
width:800px;
height:540px;
border:1px solid #ccc;/*边框 1个像素 实线条 灰色*/
border-radius:3px; /*圆角*/
box-shadow:0 0 5px #e0e0e0; /*x轴,y轴 5个大小的阴影*/
display:flex; /*弹性布局,子容器可以并排显示*/
}
#web_bg{
position:fixed;
top: 0;
left: 0;
width:100%;
height:100%;
min-width: 1000px;
z-index:-10;
zoom: 1;
background-color: #fff;
background-repeat: no-repeat;
background-size: cover;
-webkit-background-size: cover;
-o-background-size: cover;
background-position: center 0;
}
#left{
width:80%;
}
#right{
border-left: 1px solid #ccc;
width:20%;
overflow-y: auto;
overflow-x: hidden;
}
#records{
padding: 5px;
box-sizing: border-box;
overflow-y: auto;
/*calc 计算*/
height:calc(60% - 1px);
border-bottom: 1px solid #ccc;
font-size: 12px;
font-family: "SF Pro SC", "HanHei SC", "SF Pro Text", "Myriad Set Pro", "SF Pro Icons", "PingFang SC", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
}
#tools{
height:5%;
}
#contents{
height:25%;
outline: none;
padding:0px 10px; /*内间距*/
box-sizing: border-box; /*取消padding-box的增大效果*/
overflow-y: auto; /*内容处,添加垂直滚动条*/
word-wrap: break-word; /*兼容其他浏览器*/
}
#buttons{
height:10%;
text-align: right;
padding-right:10px;
box-sizing: border-box;
}
#contents_text{
width:calc(100% - 4px);
height:calc(100% - 20px);
/*无边框*/
border: none;
/*不可拖动大小*/
resize: none;
outline: none;
background-color: transparent;
}
*::-webkit-scrollbar {
width: 8px;
height: 20px;
}
*::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #9d9d9d;
}
.online{
/*行高*/
line-height: 30px;
font-family: "SF Pro SC","HanHei SC","SF Pro Text","Myriad Set Pro","SF Pro Icons","PingFang SC","Helvetica Neue","Helvetica","Arial",sans-serif;
font-size: 14px;
}
.face{
width: 20px;
height: 20px;
border-radius: 50%;
/*垂直对齐文本*/
vertical-align: middle;
/*距离右边6个像素*/
margin-right:6px;
}
.text1{
width:90px;
display: inline-block;
user-select: none;
}
.jianbian{
/*谷歌渐变效果*/
user-select: none;
position: relative;
left: -1px;
width: 10px;
display: inline-block;
background: linear-gradient(to right,black,white);
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
}
.record_face{
width: 30px;
height: 30px;
border-radius: 50%;
vertical-align: top;
}
.nickname{color: #666;}
.r{
display: flex;
float: left;
}
.rr{
display: flex;
float: right;
}
.r_left{
width: 30px;
height: 30px;
}
.r_right{margin-top: 10px;}
.message_bg{
background-color: #ccc;
padding: 10px;
border-radius: 5px;
/*让消息气泡横向不溢出*/
word-wrap:break-word;
max-width: 560px;
display:inline-block;
}
.message_bg_me{
background-color:palegreen;
padding: 10px;
border-radius: 5px;
/*让消息气泡横向不溢出*/
word-wrap:break-word;
max-width: 560px;
display:inline-block;
}
.message_line{
clear:both;
height:45px;
}
images、assets图片文件
这里我将聊天背景图和注册页面图片分成了两个图片文件,分别是images文件夹和assets文件夹,如果需要修改图片可替换图片文件,并在index.html和chat.html中修改图片索引:
<!--这里修改图片索引-->
<div id="web_bg" style="background-image: url('assets/background.jpg');">
我的图片github地址:
https://github.com/letme5/letme5.github.io
后端实现
后台使用java开发,使用了SpingBoot、WebSocket等框架。
分为config、controller、pojo三个package。
config
config下有三个类,CrossConfig用于跨域访问,RedisConfig用于后台数据管理,WebSocketConfig用于前后端交互连接。
CrossConfig类:
package com.seecen.tencent.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author liuyo
* 跨域访问
*/
@Configuration
public class CrossConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET","POST","DELETE","PUT","HEAD","OPTIONS")
.allowedHeaders("*");
}
}
**RedisConfig类:
package com.seecen.tencent.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author liuy
* 配置类,Redis默认set只能存储String类型,序列化后可以存储一个USer对象的类型
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
/*指明要连接的数据库*/
redisTemplate.setConnectionFactory(factory);
/**序列化,将内存中的对象转换为二进制类型*/
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
return redisTemplate;
}
}
WebSocket类:
package com.seecen.tencent.config;
import com.seecen.tencent.controller.ChatController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.HandshakeInterceptor;
import java.util.Map;
/**
* @author 93193
*/
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Autowired
RedisTemplate<String,Object> redisTemplate;
/**前端怎么和后端进行交互链接*/
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 前端通过ip:port/chat可以访问后台
registry.addHandler(new ChatController(redisTemplate), "/chat")
.addInterceptors(new HandshakeInterceptor() {
@Override
public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
ServletServerHttpRequest request = (ServletServerHttpRequest) serverHttpRequest;
// 获取前端用户传递过来的账户名称
String account = request.getServletRequest().getParameter("account");
map.put("account", account);
return true;
}
@Override
public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {
}
})
// 所有的前端可以访问。跨域请求开放
.setAllowedOrigins("*");
}
}
controller
ChatController类:
package com.seecen.tencent.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.seecen.tencent.pojo.ResponseEntity;
import com.seecen.tencent.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* @author liuyo
*/
public class ChatController extends AbstractWebSocketHandler {
/**ctrl+O选择覆盖的方法*/
CopyOnWriteArrayList<WebSocketSession> users =new CopyOnWriteArrayList<>();
ObjectMapper mapper = new ObjectMapper();
@Autowired
RedisTemplate<String,Object> redisTemplate;
public ChatController(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override /**重写验证*/
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
//用集合数组保存所有在线用户
Object account = session.getAttributes().get("account");
System.out.println(account+" join the chat");
//保存当前登录用户
users.add(session);
//把所有在线用户同步给所有前端
sendAllOnlineUser();
}
private void sendAllOnlineUser() throws Exception {
List<User> list = new ArrayList<>();
//遍历users集合
users.forEach(user -> {
String account = user.getAttributes().get("account").toString();
list.add((User) redisTemplate.opsForValue().get(account));
});
ResponseEntity entity = new ResponseEntity(10, "好友列表", list);
// 把entity转换为json给前端
String jsonStr = mapper.writeValueAsString(entity);
//遍历user集合,将在线用户发送给前端每个用户
sendMsg(jsonStr);
}
/**封装发送消息模块*/
private void sendMsg(String message){
users.forEach(user -> {
try {
user.sendMessage(new TextMessage(message));
} catch (IOException e) {
e.printStackTrace();
}
});
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
//当前发送者
User user = (User)redisTemplate.opsForValue().get(session.getAttributes().get("account"));
//当前发送者发送的消息
String msg = message.getPayload().toString();
ResponseEntity entity = new ResponseEntity(20,msg,user);
//把java对象转换为json字符给前端{key1:value1,key2:value2}
String jsonStr = mapper.writeValueAsString(entity);
sendMsg(jsonStr);
System.out.println("new message: "+message.getPayload().toString());
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
System.out.println("an error has occured__by liuyong");
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("User refreshes, resulting in disconnection"+users);
//把退出的人从数组中删除
users.remove(session);
sendAllOnlineUser();
}
}
UserController类:
package com.seecen.tencent.controller;
import com.seecen.tencent.pojo.ResponseEntity;
import com.seecen.tencent.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @author liuy
* Servlet/controller
* 前后端的桥梁
* 负责接收前端发送过来的请求
* 然后计算后得到结果,响应给到后端
* RestController-注册为控制器并实例化*
*/
@RestController
public class UserController {
@Autowired
RedisTemplate<String,Object> redisTemplate;
/**与前端post方式相同,精确定位到要访问的方法*/
@PostMapping("/api/register")
/**返回类型、方法名、形参*/
ResponseEntity register(@RequestBody User user){
if(redisTemplate.hasKey(user.getAccount())){
return ResponseEntity.ERROR("要注册的账户已经存在,请更换!");
}
else{
redisTemplate.opsForValue().set(user.getAccount(),user);
System.out.println(user.getAccount());
System.out.println(user.getPassword());
System.out.println(user.getFace());
return ResponseEntity.OK();
}
}
@GetMapping("/face")
public String getFace(String account){
if(redisTemplate.hasKey(account)){
User user = (User) redisTemplate.opsForValue().get(account);
return user.getFace();
}
else{
return null;
}
}
}
pojo
ResponseEntity类:
package com.seecen.tencent.pojo;
/**
* @author liuy
* 服务器响应数据对象
*/
public class ResponseEntity {
/**响应状态码*/
int code;
/**响应的消息*/
String message;
/**响应数据体*/
Object data;
public ResponseEntity(){}
/**Alt+insert快速创建构造方法*/
public ResponseEntity(int code,String message,Object data){
this.code=code;
this.message=message;
this.data=data;
}
public static ResponseEntity OK(){
ResponseEntity responseEntity = new ResponseEntity();
//状态码200表示成功
responseEntity.code =200;
responseEntity.message = "success";
return responseEntity;
}
public static ResponseEntity ERROR(String s){
ResponseEntity responseEntity = new ResponseEntity();
//状态码500表示失败
responseEntity.code =500;
responseEntity.message = "账户已存在,请检查用户名";
return responseEntity;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
User类:
package com.seecen.tencent.pojo;
import java.io.Serializable;
/**
* @author 93193
*/
public class User implements Serializable {
String account;
String password;
String face;
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFace() {
return face;
}
public void setFace(String face) {
this.face = face;
}
@Override
public String toString() {
return "User{" +
"account='" + account + '\'' +
", password='" + password + '\'' +
", face='" + face + '\'' +
'}';
}
}
服务器配置
做完以上步骤以后,就可以进行服务器配置了,由于我们后端是用java语言编写,因此在服务器上首先要装要配置好java环境,jdk可在互联网搜索下载,安装好后使用java -version命令查看java环境是否配置成功,我这里安装的是jdk1.8.0版本:
安装好java环境后还需要在服务器安装Redis、Nginx实现数据管理和访问操作,安装路径都为/usr/local。
Redis、Nginx、Maven安装包:
https://pan.baidu.com/s/1JL85E2h3sN_eUjLOPsceWg
提取码:1234
开启Redis服务
安装好Redis、Nginx之后,首先需要开启Redis服务,服务器上使用命令:
cd /usr/local/redis-3.2.9
redis-server redis.conf
开启Nginx服务
此时我们使用命令切换到Nginx安装目录的html目录下:
cd /usr/local/nginx/html
将我们写的前端页面全部文件拷贝到该目录下,目录下原先有的index.html文件将被替换。
此时我们需要启动Nginx服务,使用命令:
cd /usr/local/nginx/sbin
./nginx
开启后台Java服务
接着我们要将Java项目使用Maven进行打包,打包完成后将jar包包拷贝至/usr/local路径下,此时使用命令在服务器运行后端服务:
java -jar tencent-0.0.1-SNAPSHOT.jar //前台运行
或
java -jar tencent-0.0.1-SNAPSHOT.jar & //后台运行
出现此界面运行成功:
此时在浏览器输入我们服务器ip就能成功访问我们的web页面啦!
最后附上笔者的代码文件:
前端:https://github.com/letme5/letme5.github.io
后端:https://pan.baidu.com/s/1JL85E2h3sN_eUjLOPsceWg (提取码:1234 )
常见错误解决方法
- 检查redis 数据库是否有打开:
redis-cli
如果显示127.0.0.1:6379表示redis成功打开;显示no connect 就代表redis没有启动,需要先启动redis数据库, 启动方式:
cd /usr/local/redis-3.2.9
redis-server redis.conf
- 检查java后台程序是否启动,服务器输入:
jps
查看是否有jar的进程,如果没有,通过命令cd进入到你放置jar包的目录下,启动java服务:
java -jar (name).jar
- 启动前端页面服务器,我们放置的在Nginx服务器中如果访问 http://xxx.xxx.xxx.xxx/显示无法访问,那么大概率没有启动Nginx,服务器使用命令开启Nginx服务:
cd /usr/local/nginx/sbin
./nginx
4.如果报错显示一个 /var/run/nginx/nginx.pid not found…这个代表启动的时候会在/var/run/nginx这个目录下生成一个进程ID文件,没有的话我们创建即可,使用命令:
mkdir -p /var/run/nginx
创建完成再次启动:
./nginx