首先想要对一个项目进行二开你得把这个项目运行起来,运行项目得配置环境,而RuoYi-Vue的环境需求如下
本项目环境
环境 | win10 |
---|---|
工具 | idea 2018,vs conde |
jdk | 1.8 |
数据库 | oracle 19c |
maven | 3.5 |
缓存库 | redis |
数据库前端工具 | navicat 16 oracle |
node | v14.6.0+ |
TIP:如果node.js版本下载过高导致vue-cli项目运行报错可以修改package.json
修改前:
"scripts": {
"dev": "vite",
"build:prod": "vite build",
"build:stage": "vite build --mode staging",
"preview": "vite preview"
},
修改后:
"script":{
"dev": "set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve --open",
"build:prod": "set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build --report",
"build:stage": "set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build --mode staging",
"preview": "set NODE_OPTIONS=--openssl-legacy-provider && node build/index.js --preview",
}
运行原项目
后端
导入后端项目到idea 2018 查看pom.xml里配置,这里主要看的是oracle对应的jar 替换成你Oracle的对应的jar包就行,下面给出oracle对应的jar 包版本。
Oracle 9i: | ojdbc14.jar | (oracle.jdbc.driver.OracleDriver) |
---|---|---|
Oracle 10g: | ojdbc14.jar | (oracle.jdbc.driver.OracleDriver) |
Oracle 11g Release 1: | ojdbc5.jar | (oracle.jdbc.OracleDriver) |
Oracle 11g Release 2: | ojdbc6.jar | (oracle.jdbc.OracleDriver) |
Oracle 12c Release 1: | ojdbc6.jar | (oracle.jdbc.OracleDriver) |
Oracle 12c Release 2: | ojdbc8.jar | (oracle.jdbc.OracleDriver) |
Oracle 18c: | ojdbc8.jar | (oracle.jdbc.OracleDriver) |
Oracle 19c: | ojdbc8.jar | (oracle.jdbc.OracleDriver) |
然后查看application-druid.yml数据源的配置文件主要查看数据库的数据源配置如下一个示例
# 数据源配置
spring:
datasource:
driver-class-name: oracle.jdbc.OracleDriver
type: com.alibaba.druid.pool.DruidDataSource
druid:
# 主库数据源
master:
url: jdbc:oracle:thin:@//192.168.65.128:1521/orclpdb1
username: scott
password: tiger
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置连接超时时间
connectTimeout: 30000
# 配置网络超时时间
socketTimeout: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: lingli
login-password: 123456
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: false
wall:
config:
multi-statement-allow: true
这个示例使用的是虚拟机ip地址为192.168.65.128端口为1521的Oracle19c的一个pdcb容器的tiger用户的库。具体库替换为自己环境的库(sql文件在sql的文件夹里)
因为这个项目使用了redis缓存所以再查看application.yml的配置主要查看redis的配置下面给出一个示例配置
redis:
# 地址
host: 192.168.65.128
# 端口,默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
password:
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中的最大空闲连接
max-idle: 8
# 连接池的最大数据库连接数
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
这个示例使用的是虚拟机ip地址为192.168.65.128端口为6379的数据库索引为0的redis缓存库,替换为自己环境的设置。
导入数据都数据库到数据库后可以启动RuoYiApplication.java 出现如下图表示启动成功
打开浏览器,输入:http://localhost:8080/captchaImage,若能正确显示返回信息,搭建后台成功。
前端
导入前端项目到vs code中然后此项目中打开终端执行npm install --registry=https://registry.npm.taobao.org(如果已经设置过npm镜像源可以直接npm install)
然后在执行npm run dev(如果node版本过高报错查看前面有解决方法)
打开浏览器,输入:http://localhost:80 (默认账户 admin/admin123)
若能正确展示登录页面,并能成功登录(后端需要运行着),菜单及页面展示正常,则表明环境搭建成功
成功的示例图:
注意:执行npm命令需要配置node环境
这样原项目的就正常运行
二次开发
本次的二次开发基于课程实习要求对于原项目的首页的二次开发,成果如下:
主要添加了4个Echarts的4个图,用后端返回的数据进行渲染。
上代码
前端
将view文件下的index.vue修改成这样
<script setup>
import LineChart from './dashboard/LineChart'
import RaddarChart from './dashboard/RaddarChart'
import PieChart from './dashboard/PieChart'
import BarChart from './dashboard/BarChart'
</script>
<template>
<div class="dashboard-editor-container">
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
<LineChart />
</el-row>
<el-row :gutter="32">
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<PieChart />
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<RaddarChart />
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<BarChart />
</div>
</el-col>
</el-row>
</div>
</template>
<style lang="scss" scoped>
.dashboard-editor-container {
padding: 32px;
background-color: rgb(240, 242, 245);
position: relative;
.chart-wrapper {
background: #fff;
padding: 16px 16px 0;
margin-bottom: 32px;
}
}
@media (max-width:1024px) {
.chart-wrapper {
padding: 8px;
}
}
</style>
在view文件夹下添加一个文件夹dashboard
在dashboard下添加一个BarChart.vue代码如下
<template>
<div class="profit" id="profit" />
</template>
<script setup>
import { onMounted, ref } from 'vue'
import * as echarts from 'echarts'
import {getChart3} from '@/api/system/dept'
const list=ref([])
const data=ref([])
onMounted(()=>{
var chartDom = document.getElementById('profit');
var myChart = echarts.init(chartDom);
var option;
const colorList = [
'#4f81bd',
'#c0504d',
'#9bbb59',
'#604a7b',
'#948a54',
'#e46c0b'
];
option = {
title: {
text: '员工工资分布',
left: 'center'
},
tooltip:{},
xAxis: {
type: 'category',
data: [],
},
yAxis: {},
series: [
{
type: 'bar',
barCategoryGap: '0%', // 调整柱状图的间距
data: [],
label: {
show: true,
position: 'top'
},
itemStyle: {
color: function (params) {
return colorList[params.dataIndex];
}
}
}
]
};
option && myChart.setOption(option);
const getlist=async ()=>{
list.value=await getChart3()
data.value= list.value.map(function (item, index) {
return {
value: [item.salary_range, item.employee_count],
itemStyle: {
color: colorList[index]
}
};
});
myChart.setOption(({
xAxis: {
data: data.value.map(item => item.value[0]),
},
series:[{
data: data.value.map(item => item.value[1])
}]
}))
}
getlist()
})
</script>
<style scoped>
.profit{
width: 100%;
height: 300px;
}
</style>
在dashboard下添加一个LineChart.vue代码如下
<template>
<div class="bar" id="bar" />
</template>
<script setup>
import * as echarts from 'echarts';
import { onMounted,ref } from 'vue';
import {getChart} from '@/api/system/dept'
const chartlist=ref('')
onMounted(() => {
// 获取图表的容器
var chartDom = document.getElementById('bar');
// 初始化图表
var myChart = echarts.init(chartDom);
// 配置项
const option = {
title: {
text: '公司各部门人数',
textStyle: {
color: '#66ccff'
}
},
legend: {
data: ['深圳总公司', '长沙分公司']
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: {
type: 'category',
data: []
},
yAxis: {
type: 'value',
name: '人数',
min: 0, // 设置 y 轴的最小值
max: 5 // 设置 y 轴的最大值
},
series: [
{
name: '深圳总公司',
data: [],
type: 'bar'
},
{
name: '长沙分公司',
data: [],
type: 'bar'
}
]
};
// 使用刚指定的配置项和数据显示图表
myChart.setOption(option);
const getchartlis= async()=>{
const res=await getChart()
chartlist.value=res
let xAxisData = [];
let seriesDataGroupA = [];
let seriesDataGroupB = [];
for (let i = 0; i < chartlist.value.length; i++) {
let groupData = chartlist.value[i];
for (let group in groupData) {
let deptData = groupData[group];
for (let j = 0; j < deptData.length; j++) {
let deptName = deptData[j].deptName;
let numOfEmployees = deptData[j].numOfEmployees;
if (!xAxisData.includes(deptName)) {
xAxisData.push(deptName);
seriesDataGroupA.push(0); // 添加一个 0 作为占位
seriesDataGroupB.push(0); // 添加一个 0 作为占位
}
if (group === 'groupA') {
seriesDataGroupA[xAxisData.indexOf(deptName)] = numOfEmployees;
} else {
seriesDataGroupB[xAxisData.indexOf(deptName)] = numOfEmployees;
}
}
}
}
myChart.setOption({
xAxis: {
data: xAxisData
},
series: [
{
name: '深圳总公司',
data:seriesDataGroupA ,
type: 'bar'
},
{
name: '长沙分公司',
data: seriesDataGroupB,
type: 'bar'
}
]
})
}
getchartlis()
});
</script>
<style scoped>
.bar{
height: 350px;
width: 100%;
}
</style>
在dashboard下添加一个PieChart.vue代码如下
<template>
<div class="pie" id="pie" />
</template>
<script setup>
import * as echarts from 'echarts';
import { onMounted, ref } from 'vue';
import {getChart1} from '@/api/system/dept'
const pielist=ref([])
onMounted(()=>{
var chartDom = document.getElementById('pie');
var myChart = echarts.init(chartDom);
var option;
option = {
title: {
text: '各部门占比情况',
textStyle: {
color: '#66ccff'
}
},
legend: {
left: 'center',
bottom:'10',
},
tooltip: {
trigger: 'item'
},
series: [
{
name: '冷璃科技有限公司',
type: 'pie',
radius: [15, 95],
center: ['50%', '38%'],
roseType: 'area',
itemStyle: {
borderRadius: 8
},
data: [],
animationEasing: 'cubicInOut',
animationDuration: 2600
}
]
};
option && myChart.setOption(option);
const getpieist=async ()=>{
pielist.value=await getChart1()
myChart.setOption(({
series:[{
data:pielist.value
}]
}))
}
getpieist()
})
</script>
<style scoped>
.pie{
width: 100%;
height: 300px;
}
</style>
在dashboard下添加一个RaddarChart.vue代码如下
<template>
<div class="line" id="line" />
</template>
<script setup>
import { onMounted } from 'vue';
import * as echarts from 'echarts';
import {getChart2} from '@/api/system/dept'
const linelist=ref('')
onMounted(() => {
var chartDom = document.getElementById('line');
var myChart = echarts.init(chartDom);
var option;
option = {
title: {
text: '近期公司人员情况',
textStyle: {
color: '#66ccff'
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
xAxis: {
type: 'category',
data: []
},
yAxis: {
name:'总人数',
type: 'value'
},
series: [
{
data: [],
type: 'line',
smooth: true
}
]
};
option && myChart.setOption(option);
const getlineist=async ()=>{
linelist.value=await getChart2()
myChart.setOption(({
xAxis: {
data: linelist.value.time
},
series:[{
data:linelist.value.totalEmployees
}]
}))
}
getlineist()
});
</script>
<style scoped>
.line{
width: 100%;
height: 300px;
}
</style>
在api下的system文件夹里的dept.js里添加下面的代码
// 获取部门数据
export function getChart(){
return request({
url:'/deptchart',
method:'get'
})
}
export function getChart1(){
return request({
url:'/employeeCount',
method:'get'
})
}
export function getChart2(){
return request({
url:'/userCountByDate',
method:'get'
})
}
export function getChart3(){
return request({
url:'/userCountBySal',
method:'get'
})
}
前端改造完成
后端
往src\main\java\com\ruoyi\project\system\domain里添加3个实体SysChart、SysChart1、SysChart2代码如下
SysChart
package com.ruoyi.project.system.domain;
public class SysChart {
private String deptName;
private int numOfEmployees;
public String getDeptName() {
return deptName;
}
public int getNumOfEmployees() {
return numOfEmployees;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public void setNumOfEmployees(int numOfEmployees) {
this.numOfEmployees = numOfEmployees;
}
}
SysChart1
package com.ruoyi.project.system.domain;
public class SysChart1 {
private String time;
private int totalEmployees;
public String getTime() {
return time;
}
public int getTotalEmployees() {
return totalEmployees;
}
public void setTime(String time) {
this.time = time;
}
public void setTotalEmployees(int totalEmployees) {
this.totalEmployees = totalEmployees;
}
}
SysChart2
package com.ruoyi.project.system.domain;
public class SysChart2 {
private String salary_range;
private int employee_count;
public String getSalary_range() {
return salary_range;
}
public int getEmployee_count() {
return employee_count;
}
public void setSalary_range(String salary_range) {
this.salary_range = salary_range;
}
public void setEmployee_count(int employee_count) {
this.employee_count = employee_count;
}
}
往src\main\resources\mybatis\system里添加SysChartMapper.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="com.ruoyi.project.system.mapper.SysChartMapper">
<select id="getEmployeeCountByDept1" resultType="SysChart">
SELECT
d.DEPT_NAME AS deptName,
COUNT( e.DEPT_ID ) AS numOfEmployees
FROM
SYS_USER e
JOIN SYS_DEPT d ON e.DEPT_ID = d.DEPT_ID
WHERE
ANCESTORS LIKE '%100,101%'
GROUP BY
d.DEPT_NAME
</select>
<select id="getEmployeeCountByDept2" resultType="SysChart">
SELECT
d.DEPT_NAME AS deptName,
COUNT( e.DEPT_ID ) AS numOfEmployees
FROM
SYS_USER e
JOIN SYS_DEPT d ON e.DEPT_ID = d.DEPT_ID
WHERE
ANCESTORS LIKE '%100,102%'
GROUP BY
d.DEPT_NAME
</select>
<select id="getEmployeeCountByDept3" resultType="SysChart">
SELECT
d.DEPT_NAME AS deptName,
COUNT(e.USER_ID) AS numOfEmployees
FROM
SYS_DEPT d
JOIN SYS_USER e ON e.DEPT_ID = d.DEPT_ID
GROUP BY
d.DEPT_NAME
</select>
<select id="getEmployeeCountByDept4" resultType="SysChart1">
SELECT TO_CHAR(E.DATE1, 'MM-DD') AS time,
(SELECT COUNT(*)
FROM SYS_USER
WHERE CREATE_TIME <= E.DATE1) AS totalEmployees
FROM (SELECT TRUNC(SYSDATE) - LEVEL + 1 AS DATE1
FROM DUAL
CONNECT BY LEVEL <= 7) E
ORDER BY DATE1
</select>
<select id="getEmployeeCountByDept5" resultType="SysChart2">
<![CDATA[
SELECT
salary_range,
COUNT(*) AS employee_count
FROM
(SELECT
CASE
WHEN REMARK >= 0 AND REMARK < 6000 THEN '0-6K'
WHEN REMARK >= 6000 AND REMARK < 8000 THEN '6k-8K'
WHEN REMARK >= 8000 AND REMARK < 10000 THEN '8k-10k'
WHEN REMARK >= 10000 AND REMARK < 12000 THEN '10k-12k'
WHEN REMARK >= 12000 AND REMARK < 20000 THEN '12k-20k'
WHEN REMARK >= 20000 THEN '20k+'
END AS salary_range
FROM
SYS_POST
JOIN
SYS_USER_POST ON SYS_POST.POST_ID = SYS_USER_POST.POST_ID) subquery
GROUP BY
salary_range
ORDER BY
CASE
WHEN salary_range = '0-6K' THEN 1
WHEN salary_range = '6k-8K' THEN 2
WHEN salary_range = '8k-10k' THEN 3
WHEN salary_range = '10k-12k' THEN 4
WHEN salary_range = '12k-20k' THEN 5
WHEN salary_range = '20k+' THEN 6
END
]]>
</select>
</mapper>
往src\main\java\com\ruoyi\project\system\mapper里添加一个mapper接口SysChartMapper代码如下
package com.ruoyi.project.system.mapper;
import com.ruoyi.project.system.domain.SysChart;
import com.ruoyi.project.system.domain.SysChart1;
import com.ruoyi.project.system.domain.SysChart2;
import java.util.List;
public interface SysChartMapper {
List<SysChart> getEmployeeCountByDept1();
List<SysChart> getEmployeeCountByDept2();
List<SysChart> getEmployeeCountByDept3();
List<SysChart1> getEmployeeCountByDept4();
List<SysChart2> getEmployeeCountByDept5();
}
往src\main\java\com\ruoyi\project\system\service里添加一个接口ISysChartService代码如下
package com.ruoyi.project.system.service;
import com.ruoyi.project.system.domain.SysChart;
import java.util.List;
import java.util.Map;
public interface ISysChartService {
List<Map<String, List<SysChart>>> getEmployeeCountByDept();
List<Map<String, Object>> getDepartmentEmployeeCount();
Map<String, List<Object>> getUserCountByDate();
}
往src\main\java\com\ruoyi\project\system\service\impl里添加一个实现类SysChartServiceImpl代码如下(为了前端能直接渲染这里就给查询的数据进行了处理)
package com.ruoyi.project.system.service.impl;
import com.ruoyi.project.system.domain.SysChart;
import com.ruoyi.project.system.domain.SysChart1;
import com.ruoyi.project.system.domain.SysChart2;
import com.ruoyi.project.system.mapper.SysChartMapper;
import com.ruoyi.project.system.service.ISysChartService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class SysChartServiceImpl implements ISysChartService {
@Autowired
private SysChartMapper sysChartMapper;
@Override
public List<Map<String, List<SysChart>>> getEmployeeCountByDept() {
List<SysChart> groupA = sysChartMapper.getEmployeeCountByDept1();
List<SysChart> groupB = sysChartMapper.getEmployeeCountByDept2();
Map<String, List<SysChart>> result = new HashMap<>();
result.put("groupA", groupA);
result.put("groupB", groupB);
List<Map<String, List<SysChart>>> resultList = new ArrayList<>();
resultList.add(result);
return resultList;
}
public List<Map<String, Object>> getDepartmentEmployeeCount() {
List<SysChart> departmentEmployeeCounts =sysChartMapper.getEmployeeCountByDept3();
List<Map<String, Object>> pieChartData = new ArrayList<>();
for (SysChart count : departmentEmployeeCounts) {
Map<String, Object> data = new HashMap<>();
data.put("value", count.getNumOfEmployees());
data.put("name", count.getDeptName());
pieChartData.add(data);
}
return pieChartData;
}
public Map<String, List<Object>> getUserCountByDate() {
List<SysChart1> userList=sysChartMapper.getEmployeeCountByDept4();
List<String> timeList = new ArrayList<>();
List<Integer> totalEmployeesList = new ArrayList<>();
// 遍历查询结果,将时间和totalEmployees分别加入到对应的数组中
for (SysChart1 user : userList) {
timeList.add(user.getTime());
totalEmployeesList.add(user.getTotalEmployees());
}
// 创建一个Map来存放两个数组
Map<String, List<Object>> result = new HashMap<>();
result.put("time", new ArrayList<>(timeList));
result.put("totalEmployees", new ArrayList<>(totalEmployeesList));
return result;
}
public List<SysChart2> getUserCountBysal(){
return sysChartMapper.getEmployeeCountByDept5();
}
}
往src\main\java\com\ruoyi\project\system\controller里添加一个控制类SysChartController代码如下
package com.ruoyi.project.system.controller;
import com.ruoyi.project.system.domain.SysChart;
import com.ruoyi.project.system.domain.SysChart2;
import com.ruoyi.project.system.service.impl.SysChartServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
public class SysChartController {
@Autowired
private SysChartServiceImpl SysChartServiceImpl;
@GetMapping("/deptchart")
public List<Map<String, List<SysChart>>> getEmployeeCountByDept() {
return SysChartServiceImpl.getEmployeeCountByDept();
}
@GetMapping("/employeeCount")
public List<Map<String, Object>> getDepartmentEmployeeCount() {
return SysChartServiceImpl.getDepartmentEmployeeCount();
}
@GetMapping("/userCountByDate")
public Map<String, List<Object>> getUserCountByDate() {
return SysChartServiceImpl.getUserCountByDate();
}
@GetMapping("/userCountBySal")
public List<SysChart2> getUserCountBySal() {
return SysChartServiceImpl.getUserCountBysal();
}
}
后端代码添加完成后续可以通过接口测试工具例如postman等进行接口测试,测试能有数据返回,此项目二次开发完成。
总结
这此的二次开发涉及的知识并不多只是简单的数据的获取、处理和渲染,能花一两天的时间把这篇文章里的东西弄一个大概并运行出来。后续还会继续对这个项目进行开发。