Preface
The effect of the program is as follows: you can initialize the number of nodes, search for users and display all relationships of users, and dynamically obtain data from the database.
Front-end code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- 引入刚刚下载的 ECharts 文件 -->
<script src="js/echarts.js"></script>
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
<link rel="stylesheet" href="css/bootstrap.min.css">
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="js/bootstrap.min.js"></script>
</head>
<body>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<a class="navbar-brand" href="#">社交关系分析</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">初始化节点数(50个) <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a onclick="getRelationdataBycount(1)">页面初始化100节点</a></li>
<li><a onclick="getRelationdataBycount(2)">页面初始化200节点</a></li>
<li><a onclick="getRelationdataBycount(3)">页面初始化300节点</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" id="uname" name="uname" class="form-control" placeholder="请输入用户名">
</div>
<a class="btn btn-default" onclick="getRelationdataByUsername()">搜索用户</a>
</form>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div id="main" style="width:100%;height:1000px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
//设置只有当页面加载的时候才会执行的函数
window.onload = function () {
getRelationdata();
}
function getRelationdata() {
//首先获取所有实体,也就是nodes数据
var l_nodes = []
$.ajax({
type: "GET",
url: "http://127.0.0.1:8080/getCountNodes?count=50",
dataType: "json",
async: false,
success: function (e) {
var data = e;
var nodes = [];
for (i = 0; i < e.length; i++) {
var node = {};
node.id = data[i].uid.toString();
node.name = data[i].username
node.symbolSize = 40
node.symbol = 'circle'
nodes.push(node)
}
l_nodes = nodes;
}
});
//获取所有关系数据,也就是links数据
var l_links = []
$.ajax({
type: "GET",
url: "http://127.0.0.1:8080/getAllRelation",
dataType: "json",
async: false,
success: function (e) {
var data = e;
var links = [];
for (i = 0; i < e.length; i++) {
var link = {}
link.source = data[i].uid.toString();
link.target = data[i].subscribeUid.toString();
var relation = {}
relation.name = data[i].relationType
relation.id = "1"
link.relation = relation
links.push(link)
}
l_links = links;
}
});
var option = {
series: [{
type: 'graph',
layout: 'force',
nodes: l_nodes, //节点数据
links: l_links, //关系数据
draggable: true,//实现节点可拖拽效果
//节点的样式通过itemStyle设置
itemStyle: {
color: {
type: "radial",
x: 0.5,
y: 0.5,
r: 0.5,
colorStops: [{
offset: 0,
color: "#3dd67a", // 0% 处的颜色
},
{
offset: 0.7,
color: "#465E76", // 0% 处的颜色
},
{
offset: 1,
color: "#764650", // 100% 处的颜色
},
],
global: false, // 缺省为 false
},
},
//label设置标签样式
label: {
show: true,
position: "bottom",
distance: 5,
fontSize: 18,
align: "center",
},
autoCurveness: 0.01, //多条边的时候,自动计算曲率
edgeLabel: { //边的设置
show: true,
position: "middle",
fontSize: 12,
formatter: (params) => {
return params.data.relation.name;
},
},
edgeSymbol: ["circle", "arrow"], //边两边的类型
//只有设置了force节点之间才有排斥力
force: {
repulsion: 100,
gravity: 0.01,
edgeLength: 200
}
}],
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
}
function getRelationdataBycount(count) {
//首先获取所有实体,也就是nodes数据
var l_nodes = []
$.ajax({
type: "GET",
url: "http://127.0.0.1:8080/getCountNodes" + '?' + 'count=' + count,
dataType: "json",
async: false,
success: function (e) {
var data = e;
var nodes = [];
for (i = 0; i < e.length; i++) {
var node = {};
node.id = data[i].uid.toString();
node.name = data[i].username
node.symbolSize = 40
node.symbol = 'circle'
nodes.push(node)
}
l_nodes = nodes;
}
});
//获取所有关系数据,也就是links数据
var l_links = []
$.ajax({
type: "GET",
url: "http://127.0.0.1:8080/getAllRelation",
dataType: "json",
async: false,
success: function (e) {
var data = e;
var links = [];
for (i = 0; i < e.length; i++) {
var link = {}
link.source = data[i].uid.toString();
link.target = data[i].subscribeUid.toString();
var relation = {}
relation.name = data[i].relationType
relation.id = "1"
link.relation = relation
links.push(link)
}
l_links = links;
}
});
var option = {
series: [{
type: 'graph',
layout: 'force',
nodes: l_nodes, //节点数据
links: l_links, //关系数据
draggable: true,//实现节点可拖拽效果
//节点的样式通过itemStyle设置
itemStyle: {
color: {
type: "radial",
x: 0.5,
y: 0.5,
r: 0.5,
colorStops: [{
offset: 0,
color: "#3dd67a", // 0% 处的颜色
},
{
offset: 0.7,
color: "#465E76", // 0% 处的颜色
},
{
offset: 1,
color: "#764650", // 100% 处的颜色
},
],
global: false, // 缺省为 false
},
},
//label设置标签样式
label: {
show: true,
position: "bottom",
distance: 5,
fontSize: 18,
align: "center",
},
autoCurveness: 0.01, //多条边的时候,自动计算曲率
edgeLabel: { //边的设置
show: true,
position: "middle",
fontSize: 12,
formatter: (params) => {
return params.data.relation.name;
},
},
edgeSymbol: ["circle", "arrow"], //边两边的类型
//只有设置了force节点之间才有排斥力
force: {
repulsion: 100,
gravity: 0.01,
edgeLength: 200
}
}],
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
}
function getRelationdataByUsername() {
var uname = $("#uname").val();
if(uname==''){
alert('用户名不能为空!')
return;
}
//首先获取所有实体,也就是nodes数据
var l_nodes = []
$.ajax({
type: "GET",
url: "http://127.0.0.1:8080/getNodesByUsername"+'?'+'username='+ uname,
dataType: "json",
async: false,
success: function (e) {
var data = e;
console.log(data)
var nodes = [];
for (i = 0; i < e.length; i++) {
var node = {};
node.id = data[i].uid.toString();
node.name = data[i].username
node.symbolSize = 40
node.symbol = 'circle'
nodes.push(node)
}
l_nodes = nodes;
}
});
//获取所有关系数据,也就是links数据
var l_links = []
$.ajax({
type: "GET",
url: "http://127.0.0.1:8080/getRelationByUsername"+'?'+'username='+uname,
dataType: "json",
async: false,
success: function (e) {
var data = e;
var links = [];
for (i = 0; i < e.length; i++) {
var link = {}
link.source = data[i].uid.toString();
link.target = data[i].subscribeUid.toString();
var relation = {}
relation.name = data[i].relationType
relation.id = "1"
link.relation = relation
links.push(link)
}
l_links = links;
}
});
var option = {
series: [{
type: 'graph',
layout: 'force',
nodes: l_nodes, //节点数据
links: l_links, //关系数据
draggable: true,//实现节点可拖拽效果
//节点的样式通过itemStyle设置
itemStyle: {
color: {
type: "radial",
x: 0.5,
y: 0.5,
r: 0.5,
colorStops: [{
offset: 0,
color: "#3dd67a", // 0% 处的颜色
},
{
offset: 0.7,
color: "#465E76", // 0% 处的颜色
},
{
offset: 1,
color: "#764650", // 100% 处的颜色
},
],
global: false, // 缺省为 false
},
},
//label设置标签样式
label: {
show: true,
position: "bottom",
distance: 5,
fontSize: 18,
align: "center",
},
autoCurveness: 0.01, //多条边的时候,自动计算曲率
edgeLabel: { //边的设置
show: true,
position: "middle",
fontSize: 12,
formatter: (params) => {
return params.data.relation.name;
},
},
edgeSymbol: ["circle", "arrow"], //边两边的类型
//只有设置了force节点之间才有排斥力
force: {
repulsion: 100,
gravity: 0.01,
edgeLength: 200
}
}],
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
}
</script>
</body>
</html>
Database Design
DROP TABLE IF EXISTS `relation_info`;
CREATE TABLE `relation_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` int(11) DEFAULT NULL,
`username` varchar(100) DEFAULT NULL,
`subscribe_uid` int(11) DEFAULT NULL,
`subscribe_name` varchar(100) DEFAULT NULL,
`strong_value` int(11) DEFAULT NULL,
`relation_type` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of relation_info
-- ----------------------------
INSERT INTO `relation_info` VALUES ('1', '1', '姚明', '2', '叶莉', null, '夫妻');
INSERT INTO `relation_info` VALUES ('2', '1', '姚明', '3', '姚沁蕾', null, '女儿');
INSERT INTO `relation_info` VALUES ('3', '1', '姚明', '4', '姚志源', null, '父亲');
INSERT INTO `relation_info` VALUES ('4', '1', '姚明', '5', '方凤娣', null, '母亲');
INSERT INTO `relation_info` VALUES ('5', '1', '姚明', '6', '迈克尔.哈里斯', null, '前队友');
INSERT INTO `relation_info` VALUES ('6', '6', '迈克尔.哈里斯', '7', '易建联', null, '好友');
INSERT INTO `relation_info` VALUES ('7', '7', '易建联', '4', '姚志源', null, '好友');
INSERT INTO `relation_info` VALUES ('8', '8', '奥尼尔', '1', '姚明', null, '好友');
INSERT INTO `relation_info` VALUES ('9', '1', '姚明', '8', '奥尼尔', null, '好友');
INSERT INTO `relation_info` VALUES ('10', '9', '刘伟华', '10', '刘洋', null, '好友');
INSERT INTO `relation_info` VALUES ('11', '10', '刘洋', '1', '姚明', null, '粉丝');
INSERT INTO `relation_info` VALUES ('12', '11', '马云', '9', '刘伟华', null, '好友');
Backend implementation
Relation class
package com.atguigu.admin.bean;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("relation_info")
public class Relation {
private Long id;
private Long uid;
private String username;
private Long subscribeUid;
private String subscribeName;
private int strongValue;
private String relationType;
}
RelationMapper.xml file
<?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.atguigu.admin.mapper.RelationMapper">
<!-- public Account getAcct(Long id); -->
<select id="getAllRelation" resultType="com.atguigu.admin.bean.Relation">
select * from relation_info
</select>
<select id="getAllNodes" resultType="com.atguigu.admin.bean.Relation">
SELECT DISTINCT username,uid from relation_info UNION SELECT DISTINCT subscribe_name,subscribe_uid from relation_info
</select>
<select id="getCountNodes" resultType="com.atguigu.admin.bean.Relation">
SELECT DISTINCT username,uid from relation_info UNION SELECT DISTINCT subscribe_name,subscribe_uid from relation_info ORDER BY uid ASC LIMIT #{count}
</select>
<select id="getRelationByUserName" resultType="com.atguigu.admin.bean.Relation">
select * from relation_info WHERE username=#{username} OR subscribe_name=#{username}
</select>
<select id="getNodesByUserName" resultType="com.atguigu.admin.bean.Relation">
select DISTINCT uid,username from relation_info WHERE username=#{username} OR subscribe_name=#{username} UNION select DISTINCT subscribe_uid,subscribe_name from relation_info WHERE username=#{username} OR subscribe_name=#{username} ORDER BY uid ASC
</select>
</mapper>
RelationMapper interface file
package com.atguigu.admin.mapper;
import com.atguigu.admin.bean.Relation;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface RelationMapper {
public List<Relation> getAllRelation();
public List<Relation> getAllNodes();
public List<Relation> getCountNodes(Integer count);
public List<Relation> getRelationByUserName(String username);
public List<Relation> getNodesByUserName(String username);
}
RelationService implementation class
package com.atguigu.admin.service.imp;
import com.atguigu.admin.bean.Relation;
import com.atguigu.admin.mapper.RelationMapper;
import com.atguigu.admin.service.RelationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class RelationServiceImpl implements RelationService {
@Autowired
RelationMapper relationMapper;
@Override
public List<Relation> getAllRelation() {
return relationMapper.getAllRelation();
}
@Override
public List<Relation> getAllNodes() {
return relationMapper.getAllNodes();
}
@Override
public List<Relation> getCountNodes(Integer count) {
return relationMapper.getCountNodes(count);
}
}
SocialController class implementation
package com.atguigu.admin.controller;
import com.atguigu.admin.bean.Relation;
import com.atguigu.admin.mapper.RelationMapper;
import com.atguigu.admin.service.RelationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.List;
@Controller
public class SocialController {
@Autowired
RelationService relationService;
@ResponseBody
@GetMapping("/getAllRelation")
public List<Relation> getAllRelation(){
return relationService.getAllRelation();
}
@ResponseBody
@GetMapping("/getAllNodes")
public List<Relation> getAllNodes(){
return relationService.getAllNodes();
}
@ResponseBody
@GetMapping("/getCountNodes")
public List<Relation> getAllNodes(@RequestParam("count") Integer count){
if (count==null){
List<Relation> strings=new ArrayList<>();
return strings;
}else {
return relationService.getCountNodes(count);
}
}
@Autowired
RelationMapper relationMapper;
@ResponseBody
@GetMapping("/getRelationByUsername")
public List<Relation> getRelationByUsername(@RequestParam("username") String username){
if (username==null){
List<Relation> strings=new ArrayList<>();
return strings;
}else {
return relationMapper.getRelationByUserName(username);
}
}
@ResponseBody
@GetMapping("/getNodesByUsername")
public List<Relation> getNodesByUsername(@RequestParam("username") String username){
if (username==null){
List<Relation> strings=new ArrayList<>();
return strings;
}else {
return relationMapper.getNodesByUserName(username);
}
}
}