SpingBoot + Vue + Element UI + Echarts 整合的小 Demo
Vue 工程
- 创建 Vue 工程 (两种创建方式:vue ui 、手动初始化创建)
- 安装 Element UI、axios 插件
- 安装 Echarts 官网 https://echarts.apache.org/zh/index.html
1、执行命令
cnpm install [email protected] --save
2、main.js 中引入
import echarts from 'echarts'
Vue.prototype.$echarts = echarts
3、代码
<template>
<div id="myChart" :style="{width: '800px', height: '600px'}"></div>
</template>
<script>
export default {
name: 'Echarts',
mounted(){
// 基于准备好的dom,初始化echarts实例
let myChart = this.$echarts.init(document.getElementById('myChart'))
// 绘制图表
myChart.setOption() //一般从官网复制Option过来直接放到setOption()里面
}
}
</script>
- App.vue
<template>
<div id="app">
<div id="nav">
<router-link to="/add">添加数据</router-link> |
<router-link to="/table">数据管理</router-link> |
<router-link to="/pie">饼图</router-link> |
<router-link to="/bar">柱状图</router-link>
</div>
<div style="border:0px solid red;width: 800px;height: 600px;margin-left: 366px;">
<router-view/>
</div>
</div>
</template>
-
使用Element UI 官网 https://element.eleme.io/#/zh-CN 直接复制使用
-
Element UI 表格嵌入图片
<template slot-scope="scope">
<img :src="scope.row.icon" style="height: 70px"/>
</template>
=================================================================
<template>
<el-table
:data="tableData"
border
style="width: 100%">
<el-table-column
prop="icon"
label="图片"
width="160">
<template slot-scope="liu">
<img :src="liu.row.icon" style="height: 70px"/>
</template>
</el-table-column>
<el-table-column
fixed="right"
label="操作"
width="100">
<template slot-scope="scope">
//传递参数把操作的此行对象传入 fruitDelete(scope.row)
<el-button @click="fruitDelete(scope.row)" type="text" size="small">删除</el-button>
<el-button @click="findFruit(scope.row)" type="text" size="small">编辑</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
===============
methods: {
findFruit (object) {
this.$router.push('/edit?id=' + object.id) // 页面跳转到我们的edit页面带上id
//let id = this.$route.query.id // 获取id 在edit页面中这样获取id
},
fruitDelete (row) {
// 传入我们的数据 row
let _this = this
this.$confirm('是否确定要删除' + row.name + '?', '删除数据', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 点击确定就进入这个回调中
_this.$axios.delete('http://localhost:8181/fruit/delete/' + row.id).then(function (response) {
if (response.data) {
_this.$alert(row.name + '删除成功!', '删除数据', {
confirmButtonText: '确定',
callback: action => {
// 跳转到/table
location.reload() // 点击确定就执行这个 ---刷新页面
}
})
}
})
}).catch(() => {
})
}
},
======================
// get 去请求 then 去回调
// this 表示的vue对象,在回调中我们拿的是回调的对象 所以我们设置_this来表示全局的对象
created () {
let _this = this
this.$axios.get('http://localhost:8181/fruit/list').then(function (response) {
_this.tableData = response.data
})
},
=====================
data () {
return {
tableData: null
}
}
}
</script>
- 数据校验
<template>
<el-form ref="fruitRules" :model="fruit" :rules="rules" label-width="80px" class="demo-ruleForm" style="width: 600px">
<!-- prop 就是跟我们的校验规则绑定的-->
<el-form-item label="名称" prop="name">
<el-input v-model="fruit.name"></el-input>
</el-form-item>
<el-form-item label="销量" prop="sale">
<el-input v-model.number="fruit.sale"></el-input>
</el-form-item>
<el-form-item label="图片" prop="icon">
<el-input v-model="fruit.icon"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit('fruitRules')">立即创建</el-button>
<el-button @click="onSubmit1('form')">取消</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
name: "Add",
data() {
return {
fruit: {
name: '',
sale: '',
icon: ''
},
rules:{
//数据校验规则
// required 必填项 如果不填就打印 message,trigger表示什么时候触发,blur表示光标离开的时候
name:[
{
required: true, message: '请输入水果名称', trigger: 'blur' }
],
sale:[
{
required: true, message: '请输入销量', trigger: 'blur' },
{
type: 'number', message: '销量必须为数字值'}
],
icon:[
{
required: true, message: '请输入图片链接', trigger: 'blur' }
]
}
}
},
methods: {
onSubmit(formName){
this.$refs[formName].validate((valid) => {
if (valid) {
let _this = this
axios.post('http://localhost:8181/fruit/add',this.fruit).then(function (response) {
if(response.data){
_this.$alert(_this.fruit.name+'添加成功!', '添加数据', {
confirmButtonText: '确定',
callback: action => {
//跳转到/table
_this.$router.push('/table')
}
});
}
})
}
});
},
onSubmit1(formName){
this.$router.push('/table') //取消就回到首页
}
}
}
</script>
<style scoped>
</style>
- APP、Table、Edit、Add、Bar、Pie.Vue
<template>
<div id="app">
<div id="nav">
<!-- <router-link to="/add">添加数据</router-link> |-->
<router-link to="/add">添加数据</router-link> |
<router-link to="/table">数据管理</router-link> |
<router-link to="/pie">饼图</router-link> |
<router-link to="/bar">柱状图</router-link>
</div>
<div style="border:0px solid red;width: 800px;height: 600px;margin-left: 400px;">
<router-view/>
</div>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<!--=====================================================================================================-->
<template>
<el-table
:data="tableData"
border
style="width: 100%">
<el-table-column
fixed
prop="id"
label="水果ID"
width="160">
</el-table-column>
<el-table-column
prop="name"
label="水果名称"
width="160">
</el-table-column>
<el-table-column
prop="sale"
label="水果销量"
width="160">
</el-table-column>
<el-table-column
prop="icon"
label="图片"
width="160">
<template slot-scope="liu">
<img :src="liu.row.icon" style="height: 70px"/>
</template>
</el-table-column>
<el-table-column
fixed="right"
label="操作"
width="100">
<template slot-scope="scope">
<el-button @click="fruitDelete(scope.row)" type="text" size="small">删除</el-button>
<el-button @click="findFruit(scope.row)" type="text" size="small">编辑</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
methods: {
findFruit (object) {
this.$router.push('/edit?id=' + object.id) // 页面跳转到我们的edit页面带上id
},
fruitDelete (row) {
// 传入我们的数据 row
let _this = this
this.$confirm('是否确定要删除' + row.name + '?', '删除数据', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 点击确定就进入这个回调中
_this.$axios.delete('http://localhost:8181/fruit/delete/' + row.id).then(function (response) {
if (response.data) {
_this.$alert(row.name + '删除成功!', '删除数据', {
confirmButtonText: '确定',
callback: action => {
// 跳转到/table
location.reload() // 点击确定就执行这个 ---刷新页面
}
})
}
})
}).catch(() => {
})
}
},
// get 去请求 then 去回调
// this 表示的vue对象,在回调中我们拿的是回调的对象 所以我们设置_this来表示全局的对象
created () {
let _this = this
this.$axios.get('http://localhost:8181/fruit/list').then(function (response) {
_this.tableData = response.data
})
},
data () {
return {
tableData: null
}
}
}
</script>
<!--=====================================================================================================-->
<template>
<el-form ref="form" :rules="rules" :model="fruit" label-width="80px" style="width: 600px">
<el-form-item label="水果ID">
<el-input v-model="fruit.id" readonly></el-input>
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="fruit.name"></el-input>
</el-form-item>
<el-form-item label="销量" prop="sale">
<el-input v-model.number="fruit.sale"></el-input>
</el-form-item>
<el-form-item label="图片" prop="icon">
<!-- // prop 就是跟我们的校验规则绑定的-->
<el-input v-model="fruit.icon"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit('form')">立即修改</el-button>
<el-button @click="onSubmit1('form')">取消</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
name: "Edit",
data () {
return {
fruit: {
name: '',
sale: '',
icon: ''
},
rules:{
name:[
{
required: true, message: '请输入水果名称', trigger: 'blur' } // required 必填项 如果不填就打印 message,trigger表示什么时候触发,blur表示光标离开的时候
],
sale:[
{
required: true, message: '请输入销量', trigger: 'blur' },
{
type: 'number', message: '销量必须为数字值'}
],
icon:[
{
required: true, message: '请输入图片链接', trigger: 'blur' }
]
}
}
},
created() {
let id = this.$route.query.id // 获取id
let _this = this
this.$axios.get('http://localhost:8181/fruit/find/'+id).then(function (response) {
_this.fruit = response.data
})
},
methods: {
onSubmit(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
let _this = this
this.$axios.put('http://localhost:8181/fruit/update',this.fruit).then(function (response) {
if(response.data){
_this.$alert(_this.fruit.name+'修改成功!', '修改数据', {
confirmButtonText: '确定',
callback: action => {
//跳转到/table
_this.$router.push('/table')
}
});
}
})
}
});
},
onSubmit1(formName){
this.$router.push('/table')
}
}
}
</script>
<style scoped>
</style>
<!--=====================================================================================================-->
<template>
<el-form ref="fruitRules" :model="fruit" :rules="rules" label-width="80px" class="demo-ruleForm" style="width: 600px">
<el-form-item label="名称" prop="name">
<el-input v-model="fruit.name"></el-input>
</el-form-item>
<el-form-item label="销量" prop="sale">
<el-input v-model.number="fruit.sale"></el-input>
</el-form-item>
<el-form-item label="图片" prop="icon">
<el-input v-model="fruit.icon"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit('fruitRules')">立即创建</el-button>
<el-button @click="onSubmit1('form')">取消</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
name: "Add",
data() {
return {
fruit: {
name: '',
sale: '',
icon: ''
},
rules:{
name:[
{
required: true, message: '请输入水果名称', trigger: 'blur' }
],
sale:[
{
required: true, message: '请输入销量', trigger: 'blur' },
{
type: 'number', message: '销量必须为数字值'}
],
icon:[
{
required: true, message: '请输入图片链接', trigger: 'blur' }
]
}
}
},
methods: {
onSubmit(formName){
this.$refs[formName].validate((valid) => {
if (valid) {
let _this = this
this.$axios.post('http://localhost:8181/fruit/add',this.fruit).then(function (response) {
if(response.data){
_this.$alert(_this.fruit.name+'添加成功!', '添加数据', {
confirmButtonText: '确定',
callback: action => {
//跳转到/table
_this.$router.push('/table')
}
});
}
})
}
});
},
onSubmit1(formName){
this.$router.push('/table')
}
}
}
</script>
<style scoped>
</style>
<!--=====================================================================================================-->
<template>
<div id="myChart" :style="{width: '800px', height: '600px'}"></div>
</template>
<script>
export default {
name: 'Echarts',
mounted () {
let _this = this
this.$axios('http://localhost:8181//fruit/barVO').then(function (response) {
// 基于准备好的dom,初始化echarts实例
let myChart = _this.$echarts.init(document.getElementById('myChart'))
// 绘制图表
myChart.setOption({
title: {
text: '水果销量统计',
left: 'center',
top: 20,
textStyle: {
color: '#555555'
}
},
tooltip: {
},
xAxis: {
data: response.data.names
},
yAxis: {
},
series: [{
name: '销量',
type: 'bar',
data: response.data.values
}]
})
})
}
}
</script>
<!--=====================================================================================================-->
<template>
<div id="myChart" :style="{width: '800px', height: '600px'}"></div>
</template>
<script>
export default {
name: 'Echarts',
mounted () {
let _this = this
this.$axios.get('http://localhost:8181//fruit/pieVO').then(function (response) {
// 基于准备好的dom,初始化echarts实例
let myChart = _this.$echarts.init(document.getElementById('myChart'))
// 绘制图表
myChart.setOption({
backgroundColor: '#2c343c',
title: {
text: '水果销量统计',
left: 'center',
top: 20,
textStyle: {
color: '#ccc'
}
},
tooltip: {
trigger: 'item'
},
visualMap: {
show: false,
min: 80,
max: 600,
inRange: {
colorLightness: [0, 1]
}
},
series: [
{
name: '访问来源',
type: 'pie',
radius: '55%',
center: ['50%', '50%'],
data:
// response.data 来表示回调的数据
response.data.sort(function (a, b) {
return a.value - b.value; }),
roseType: 'radius',
label: {
color: 'rgba(255, 255, 255, 0.3)'
},
labelLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
},
smooth: 0.2,
length: 10,
length2: 20
},
itemStyle: {
color: '#c23531',
shadowBlur: 200,
shadowColor: 'rgba(0, 0, 0, 0.5)'
},
animationType: 'scale',
animationEasing: 'elasticOut',
animationDelay: function (idx) {
return Math.random() * 200
}
}
]
})
})
}
}
</script>
- main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import axios from 'axios'
import Echarts from 'echarts'
Vue.prototype.$echarts = Echarts
Vue.prototype.$axios = axios
Vue.use(Element)
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: {
App },
template: '<App/>'
})
- index.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import axios from 'axios'
import Echarts from 'echarts'
Vue.prototype.$echarts = Echarts
Vue.prototype.$axios = axios
Vue.use(Element)
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: {
App },
template: '<App/>'
})
Spring Boot 工程
- pom.xml 导入 MBP 依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!--代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.2</version>
</dependency>
<!--模板-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
- 代码生成器
package com.liu;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
public class GenerateTest {
public static void main(String[] args) {
//创建generator对象
AutoGenerator autoGenerator = new AutoGenerator();
//数据源
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDbType(DbType.MYSQL);//选择数据库类型
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("1234");
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/test11");
autoGenerator.setDataSource(dataSourceConfig);//将数据源组装到Generator中
//全局配置
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");
globalConfig.setAuthor("admin"); //代码生成后会有注释,上面会写作者
globalConfig.setOpen(false); //项目文件路径是否自动打开
globalConfig.setServiceName("%sService");
autoGenerator.setGlobalConfig(globalConfig);
//包信息
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.liu"); //设置父包
packageConfig.setEntity("entity"); //设置子包
packageConfig.setMapper("mapper");
packageConfig.setService("service");
packageConfig.setServiceImpl("service.impl");
packageConfig.setController("controller");
autoGenerator.setPackageInfo(packageConfig);
//策略配置 跟数据库相关的东西
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setInclude("fruit"); //相关表
strategyConfig.setNaming(NamingStrategy.underline_to_camel); //设置实体 下划线转驼峰
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel); //设置字段 下划线转驼峰
strategyConfig.setEntityLombokModel(true); //自动加lombok
autoGenerator.setStrategy(strategyConfig);
//运行
autoGenerator.execute();
}
}
- application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/test11
username: root
password: 1234
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 打印sql语句
mapper-locations: classpath:com/southwind/mapper/xml/*.xml 把xml扫描进来
server:
port: 8181
- 跨域
package com.liu.configuration;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CrosConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
- 没有在yml中配置数据源 导致出错
- 跨域