功能示範
後端:Spring boot + MyBatis-Plus
前端:Vue + Element UI + ECharts + Axios
建立 Vue 工程
安裝 Vue 及腳手架:
參考:https://blog.csdn.net/dream_summer/article/details/108867317
在 cmd 輸入
vue ui
指令,打開 Vue 項目管理器:
建立新項目:
選擇【建立】→【編輯路徑】→點選【在此建立新項目】→【詳情】→【預設】→【功能】→【配置】→點選【建立項目】
安裝插件:
選擇【插件】→【添加插件】→【查找插件】→【安裝插件】→【完成安裝】
用 IDEA 打開項目,在 Terminal 終端輸入
npm run serve
指令,嘗試運作:
成功建立 Vue 工程。
使用 Element UI 和 ECharts
編寫 Bar.vue 元件,用于繪制柱狀圖:
<template>
<div id="myChart" :style="{width: '800px', height: '600px'}"></div>
</template>
<script>
export default {
name: "Bar",
mounted() {
// 基于準備好的dom,初始化echarts執行個體
let myChart = this.$echarts.init(document.getElementById('myChart'))
// 繪制圖表,setOption的内容可以按需替換
myChart.setOption({
title: {
text: '水果銷量統計-柱狀圖',
left: 'center',
top: 20,
textStyle: {
color: '#555555',
},
},
tooltip: {},
xAxis: {
data: [
"蘋果",
"香蕉",
"橘子",
"火龍果",
"葡萄",
"西瓜",
],
},
yAxis: {},
series: [{
name: '銷量',
type: 'bar',
data: [
{
value: 333,
itemStyle: {color: "#f35959"},
},
{
value: 133,
itemStyle: {color: "#e7e694"},
},
{
value: 99,
itemStyle: {color: "#e87f47"},
},
{
value: 222,
itemStyle: {color: "#5fa54e"},
},
{
value: 399,
itemStyle: {color: "#7d5f9a"},
},
{
value: 123,
itemStyle: {color: "#3b9265"},
},
],
}],
});
}
}
</script>
在 router.js 中配置路由:
{
path: '/bar', // 路由位址
component: () => import('./views/Bar') // 對應跳轉的元件
},
在 App.vue 中添加
<router-view/>
,當浏覽器通路時,可以替換成指定的元件:
在 ECharts 網站中,可以選擇各類圖表的模闆:
另外,在 Element 網站中,可以選擇各類元件的模闆:
搭建後端服務
在 IDEA 中建立 Spring Boot 項目:
直接添加依賴:
在 pom.xml 中導入 MyBatis-Plus 依賴:
<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>
編寫 MyBatis-Plus 的代碼生成器,所有配置都可以使用 Java Config 完成:
package com.example;
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("123456"); // 登入密碼
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/fruit"); // url
autoGenerator.setDataSource(dataSourceConfig);
// 全局配置
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java"); // user.dir擷取目前工程的src目錄路徑
globalConfig.setAuthor("admin"); // 注釋作者
globalConfig.setOpen(false); // 生成代碼後是否打開資料總管
globalConfig.setFileOverride(false); // 重新生成代碼後是否覆寫原檔案
globalConfig.setServiceName("%sService"); // 去掉Service接口的首字母I
autoGenerator.setGlobalConfig(globalConfig);
// 包資訊配置
PackageConfig packageConfig = new PackageConfig();
packageConfig.setModuleName(null); // 子產品名
packageConfig.setParent("com.example"); // 包名
packageConfig.setController("controller"); // 前端控制器,控制請求和響應,負責前後端互動
packageConfig.setEntity("entity"); // 存放實體類,一張資料庫表對應一個model類
packageConfig.setMapper("mapper"); // 資料存儲對象,作用是通路資料庫,向資料庫發送sql語句,完成資料的增删改查任務
packageConfig.setService("service"); // 資料服務層,負責調用mapper的接口進行業務邏輯應用的處理
packageConfig.setServiceImpl("service.impl"); // 資料服務的實作接口,把mapper和service進行整合
autoGenerator.setPackageInfo(packageConfig);
// 政策配置
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setInclude("fruit_info"); // 資料庫表名,可以指定多個表進行處理
strategyConfig.setNaming(NamingStrategy.underline_to_camel); // 資料庫表名映射到實體類的命名政策,underline_to_camel表示下劃線轉駝峰
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel); // 資料庫表字段名映射到成員變量的命名政策
strategyConfig.setEntityLombokModel(true); // 是否使用Lombok注解
autoGenerator.setStrategy(strategyConfig);
// 運作
autoGenerator.execute();
}
}
運作其中的 main 方法,就可以生成 Entity、Mapper、Service、Controller 子產品代碼:
在 application.yml 中添加配置資訊:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/fruit
username: root
password: 123456
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath:com/example/mapper/xml/*.xml
server:
port: 8181
在 FruitInfoController 中編寫增删改查資料接口:
package com.example.controller;
import com.example.entity.FruitInfo;
import com.example.service.FruitInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* <p>
* 前端控制器
* </p>
*
* @author admin
* @since 2021-08-11
*/
@RestController
@RequestMapping("/fruitInfo")
public class FruitInfoController {
@Autowired
private FruitInfoService fruitInfoService;
// 查詢資料接口
@GetMapping("/list")
public List<FruitInfo> list() {
return this.fruitInfoService.list();
}
// 删除資料接口
@DeleteMapping("/delete/{id}")
public boolean delete(@PathVariable("id") Integer id) {
return this.fruitInfoService.removeById(id);
}
// 編輯資料接口
@GetMapping("/find/{id}")
public FruitInfo find(@PathVariable("id") Integer id) {
return this.fruitInfoService.getById(id);
}
// 更新資料接口
@PutMapping("/update")
public boolean update(@RequestBody FruitInfo fruitInfo) {
return this.fruitInfoService.updateById(fruitInfo);
}
// 添加資料接口
@PostMapping("/add")
public boolean add(@RequestBody FruitInfo fruitInfo) {
return this.fruitInfoService.save(fruitInfo);
}
}
運作程式,測試查詢資料接口:
前後端資料對接
使用 Axios 連接配接查詢資料接口:
// 連接配接查詢資料接口
axios
.get('http://localhost:8181/fruitInfo/list')
.then(function(response) {
that.tableData = response.data; // 傳回所有資料
});
在背景添加 configuration 檔案,解決跨域問題:
package com.example.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("*") // 允許送出請求的方法
.allowedHeaders("*") // 允許通路的頭資訊
.maxAge(3600) // 預請求的結果有效期
.allowCredentials(true);
}
}
編寫 Table.vue 元件,用于查詢資料和删除資料:
<template>
<el-table :data="tableData" border style="width: 100%"
:cell-style="rowClass" :header-cell-style="headClass">
<el-table-column prop="id" label="水果ID" width="150"></el-table-column>
<el-table-column prop="name" label="水果名稱" width="150"></el-table-column>
<el-table-column prop="sale" label="水果銷量" width="150"></el-table-column>
<el-table-column prop="icon" label="圖檔" width="150">
<template slot-scope="scope">
<img :src="scope.row.icon" style="width: 100px; height: 100px" />
</template>
</el-table-column>
<el-table-column label="操作" width="150">
<template slot-scope="scope">
<el-button @click="findFruit(scope.row)" type="text" size="small">編輯</el-button>
<el-button @click="deleteFruit(scope.row)" type="text" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
name: "Table",
methods: {
// 表頭内容樣式設定
headClass() {
return 'text-align: center;';
},
// 表格内容樣式設定
rowClass() {
return 'text-align: center;';
},
// 編輯資料操作
findFruit(row) {
this.$router.push('/edit?id='+row.id); // 跳轉到/edit頁面
},
// 删除資料操作
deleteFruit(row) {
let that = this;
this.$confirm('是否确定删除'+row.name+'?', '删除資料', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => { // 點選确定
// 連接配接删除資料接口
axios
.delete('http://localhost:8181/fruitInfo/delete/'+row.id)
.then(function(response) {
if(response.data) { // 接口傳回bool類型,true表示删除成功
that.$alert('删除成功!', '删除資料', {
confirmButtonText: '确定',
callback: action => {
location.reload(); // 重新整理目前頁面
}
});
}
})
}).catch(() => { // 點選取消
});
},
},
// 顯示表格資料
created() {
let that = this;
// 連接配接查詢資料接口
axios
.get('http://localhost:8181/fruitInfo/list')
.then(function(response) {
that.tableData = response.data; // 傳回所有資料
});
},
// 預設表格資料
data() {
return {
tableData: null,
};
},
}
</script>
編寫 Edit.vue 元件,用于編輯資料和更新資料:
<template>
<el-form ref="fruitRules" :model="fruitData" :rules="rules"
label-width="80px" style="width: 600px" class="demo-ruleForm">
<el-form-item label="水果ID" prop="id">
<el-input v-model="fruitData.id" readonly></el-input>
</el-form-item>
<el-form-item label="水果名稱" prop="name">
<el-input v-model="fruitData.name"></el-input>
</el-form-item>
<el-form-item label="水果銷量" prop="sale">
<el-input v-model.number="fruitData.sale"></el-input>
</el-form-item>
<el-form-item label="圖檔" prop="icon">
<el-input v-model="fruitData.icon"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit('fruitRules')">立即修改</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
name: "Edit",
methods: {
onSubmit(formName){
this.$refs[formName].validate((valid) => {
if(valid) {
let that = this;
// 連接配接更新資料接口
axios
.put('http://localhost:8181/fruitInfo/update', this.fruitData)
.then(function (response) {
if(response.data){
that.$alert(that.fruitData.name+'修改成功!', '修改資料', {
confirmButtonText: '确定',
callback: action => {
that.$router.push('/table'); // 跳轉到/table頁面
}
});
}
});
}
});
}
},
// 顯示表格資料
created() {
let id = this.$route.query.id;
let that = this;
// 連接配接編輯資料接口
axios
.get('http://localhost:8181/fruitInfo/find/'+id)
.then(function(response) {
that.fruitData = response.data; // 傳回對應id的資料
});
},
data() {
return {
fruitData: {
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' },
],
},
}
},
}
</script>
編寫 Add.vue 元件,用于添加資料:
<template>
<el-form ref="fruitRules" :model="fruitData" :rules="rules"
label-width="80px" style="width: 600px" class="demo-ruleForm">
<el-form-item label="水果ID" prop="id">
<el-input v-model="fruitData.id"></el-input>
</el-form-item>
<el-form-item label="水果名稱" prop="name">
<el-input v-model="fruitData.name"></el-input>
</el-form-item>
<el-form-item label="水果銷量" prop="sale">
<el-input v-model.number="fruitData.sale"></el-input>
</el-form-item>
<el-form-item label="圖檔" prop="icon">
<el-input v-model="fruitData.icon"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit('fruitRules')">立即建立</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
name: "Add",
methods: {
onSubmit(formName){
this.$refs[formName].validate((valid) => {
if(valid) {
let that = this;
// 連接配接添加資料接口
axios
.post('http://localhost:8181/fruitInfo/add', this.fruitData)
.then(function (response) {
if(response.data){
that.$alert(that.fruitData.name+'添加成功!', '添加資料', {
confirmButtonText: '确定',
callback: action => {
that.$router.push('/table'); // 跳轉到/table頁面
}
});
}
});
}
});
}
},
data() {
return {
fruitData: {
id: '',
name: '',
sale: '',
icon: '',
},
rules:{
id:[
{ required: true, message: '請輸入水果ID', trigger: 'blur' },
],
name:[
{ required: true, message: '請輸入水果名稱', trigger: 'blur' },
],
sale:[
{ required: true, message: '請輸入水果銷量', trigger: 'blur' },
{ type: 'number', message: '水果銷量必須為數字值'},
],
icon:[
{ required: true, message: '請輸入圖檔連結', trigger: 'blur' },
],
},
}
},
}
</script>