管理頁面
主要就是mybatis-plus使用,以及前端表單驗證。
MyBatis是一款非常熱門的數(shù)據(jù)操作層(持久層)框架。
優(yōu)點:
- 自定義SQL ,滿足所有的復(fù)雜查詢,方便SQL優(yōu)化。
- 相對(JPA)來說上手簡單一些。
mybatis-plus ?
Mybatis-Plus(簡稱MP)是一個 Mybatis 的增強工具,在 Mybatis 的基礎(chǔ)上只做增強不做改變,為簡化開發(fā)、提高效率而生。參考mybatis-plus官網(wǎng)。其實就是它已經(jīng)封裝好了一些crud方法,我們不需要再寫xml了,直接調(diào)用這些方法就行,就類似于JPA。
效果圖:

列表

新增/修改
主要依賴:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
直接在配置文件添加配置參數(shù)即可:
spring:
......
mybatis-plus:
global-config:
#主鍵類型 0:"數(shù)據(jù)庫ID自增", 1:"用戶輸入ID",2:"全局唯一ID (數(shù)字類型唯一ID)", 3:"全局唯一ID UUID";
id-type: 0
#字段策略 0:"忽略判斷",1:"非 NULL 判斷"),2:"非空判斷"
field-strategy: 2
#駝峰下劃線轉(zhuǎn)換
db-column-underline: true
#刷新mapper 調(diào)試神器
refresh-mapper: true
#數(shù)據(jù)庫大寫下劃線轉(zhuǎn)換
#capital-mode: true
#序列接口實現(xiàn)類配置
#key-generator: com.baomidou.springboot.xxx
#邏輯刪除配置
#logic-delete-value: 0
#logic-not-delete-value: 1
#自定義填充策略接口實現(xiàn)
#meta-object-handler: com.umeox.waas.domain.handler.MyMetaObjectHandler
#自定義SQL注入器
#sql-injector: com.baomidou.springboot.xxx
configuration:
map-underscore-to-camel-case: true #entity類字段名映射表字段名
cache-enabled: false
MyBatis-Plus使用:
public interface IService<T> {
/**
* <p>
* 插入一條記錄(選擇字段,策略插入)
* </p>
*
* @param entity 實體對象
* @return boolean
*/
boolean insert(T entity);
/**
* <p>
* 插入一條記錄(全部字段)
* </p>
*
* @param entity 實體對象
* @return boolean
*/
boolean insertAllColumn(T entity);
/**
* <p>
* 插入(批量),該方法不適合 Oracle
* </p>
*
* @param entityList 實體對象列表
* @return boolean
*/
boolean insertBatch(List<T> entityList);
/**
* <p>
* 插入(批量)
* </p>
*
* @param entityList 實體對象列表
* @param batchSize 插入批次數(shù)量
* @return boolean
*/
boolean insertBatch(List<T> entityList, int batchSize);
/**
* <p>
* 批量修改插入
* </p>
*
* @param entityList 實體對象列表
* @return boolean
*/
boolean insertOrUpdateBatch(List<T> entityList);
/**
* <p>
* 批量修改插入
* </p>
*
* @param entityList 實體對象列表
* @param batchSize
* @return boolean
*/
boolean insertOrUpdateBatch(List<T> entityList, int batchSize);
/**
* <p>
* 批量修改或插入全部字段
* </p>
*
* @param entityList 實體對象列表
* @return boolean
*/
boolean insertOrUpdateAllColumnBatch(List<T> entityList);
/**
* 批量修改或插入全部字段
*
* @param entityList 實體對象列表
* @param batchSize
* @return boolean
*/
boolean insertOrUpdateAllColumnBatch(List<T> entityList, int batchSize);
/**
* <p>
* 根據(jù) ID 刪除
* </p>
*
* @param id 主鍵ID
* @return boolean
*/
boolean deleteById(Serializable id);
/**
* <p>
* 根據(jù) columnMap 條件,刪除記錄
* </p>
*
* @param columnMap 表字段 map 對象
* @return boolean
*/
boolean deleteByMap(Map<String, Object> columnMap);
/**
* <p>
* 根據(jù) entity 條件,刪除記錄
* </p>
*
* @param wrapper 實體包裝類 {@link Wrapper}
* @return boolean
*/
boolean delete(Wrapper<T> wrapper);
/**
* <p>
* 刪除(根據(jù)ID 批量刪除)
* </p>
*
* @param idList 主鍵ID列表
* @return boolean
*/
boolean deleteBatchIds(Collection<? extends Serializable> idList);
/**
* <p>
* 根據(jù) ID 選擇修改
* </p>
*
* @param entity 實體對象
* @return boolean
*/
boolean updateById(T entity);
/**
* <p>
* 根據(jù) ID 修改全部字段
* </p>
*
* @param entity 實體對象
* @return boolean
*/
boolean updateAllColumnById(T entity);
/**
* <p>
* 根據(jù) whereEntity 條件,更新記錄
* </p>
*
* @param entity 實體對象
* @param wrapper 實體包裝類 {@link Wrapper}
* @return boolean
*/
boolean update(T entity, Wrapper<T> wrapper);
/**
* <p>
* 根據(jù) whereEntity 條件,自定義set值更新記錄
* </p>
*
* @param setStr set值字符串
* @param wrapper 實體包裝類 {@link Wrapper}
* @return boolean
*/
boolean updateForSet(String setStr, Wrapper<T> wrapper);
/**
* <p>
* 根據(jù)ID 批量更新
* </p>
*
* @param entityList 實體對象列表
* @return boolean
*/
boolean updateBatchById(List<T> entityList);
/**
* <p>
* 根據(jù)ID 批量更新
* </p>
*
* @param entityList 實體對象列表
* @param batchSize 更新批次數(shù)量
* @return boolean
*/
boolean updateBatchById(List<T> entityList, int batchSize);
/**
* <p>
* 根據(jù)ID 批量更新全部字段
* </p>
*
* @param entityList 實體對象列表
* @return boolean
*/
boolean updateAllColumnBatchById(List<T> entityList);
/**
* <p>
* 根據(jù)ID 批量更新全部字段
* </p>
*
* @param entityList 實體對象列表
* @param batchSize 更新批次數(shù)量
* @return boolean
*/
boolean updateAllColumnBatchById(List<T> entityList, int batchSize);
/**
* <p>
* TableId 注解存在更新記錄,否插入一條記錄
* </p>
*
* @param entity 實體對象
* @return boolean
*/
boolean insertOrUpdate(T entity);
/**
* 插入或修改一條記錄的全部字段
*
* @param entity 實體對象
* @return boolean
*/
boolean insertOrUpdateAllColumn(T entity);
/**
* <p>
* 根據(jù) ID 查詢
* </p>
*
* @param id 主鍵ID
* @return T
*/
T selectById(Serializable id);
/**
* <p>
* 查詢(根據(jù)ID 批量查詢)
* </p>
*
* @param idList 主鍵ID列表
* @return List<T>
*/
List<T> selectBatchIds(Collection<? extends Serializable> idList);
/**
* <p>
* 查詢(根據(jù) columnMap 條件)
* </p>
*
* @param columnMap 表字段 map 對象
* @return List<T>
*/
List<T> selectByMap(Map<String, Object> columnMap);
/**
* <p>
* 根據(jù) Wrapper,查詢一條記錄
* </p>
*
* @param wrapper 實體對象
* @return T
*/
T selectOne(Wrapper<T> wrapper);
/**
* <p>
* 根據(jù) Wrapper,查詢一條記錄
* </p>
*
* @param wrapper {@link Wrapper}
* @return Map<String,Object>
*/
Map<String, Object> selectMap(Wrapper<T> wrapper);
/**
* <p>
* 根據(jù) Wrapper,查詢一條記錄
* </p>
*
* @param wrapper {@link Wrapper}
* @return Object
*/
Object selectObj(Wrapper<T> wrapper);
/**
* <p>
* 根據(jù) Wrapper 條件,查詢總記錄數(shù)
* </p>
*
* @param wrapper 實體對象
* @return int
*/
int selectCount(Wrapper<T> wrapper);
/**
* <p>
* 查詢列表
* </p>
*
* @param wrapper 實體包裝類 {@link Wrapper}
* @return
*/
List<T> selectList(Wrapper<T> wrapper);
/**
* <p>
* 翻頁查詢
* </p>
*
* @param page 翻頁對象
* @return
*/
Page<T> selectPage(Page<T> page);
/**
* <p>
* 查詢列表
* </p>
*
* @param wrapper {@link Wrapper}
* @return
*/
List<Map<String, Object>> selectMaps(Wrapper<T> wrapper);
/**
* <p>
* 根據(jù) Wrapper 條件,查詢?nèi)坑涗? * </p>
*
* @param wrapper 實體對象封裝操作類(可以為 null)
* @return List<Object>
*/
List<Object> selectObjs(Wrapper<T> wrapper);
/**
* <p>
* 翻頁查詢
* </p>
*
* @param page 翻頁對象
* @param wrapper {@link Wrapper}
* @return
*/
@SuppressWarnings("rawtypes")
Page<Map<String, Object>> selectMapsPage(Page page, Wrapper<T> wrapper);
/**
* <p>
* 翻頁查詢
* </p>
*
* @param page 翻頁對象
* @param wrapper 實體包裝類 {@link Wrapper}
* @return
*/
Page<T> selectPage(Page<T> page, Wrapper<T> wrapper);
}
需要繼承的基礎(chǔ)接口,有默認的實現(xiàn)。(以菜單為例)
新增操作單個或者數(shù)組批量新增。直接調(diào)用相應(yīng)的方法即可
-
修改, 根據(jù)ID修改。
只修改一個字段,或者某幾個字段。# 不為null的屬性都會被修改。 反之如果不想修改的屬性直接設(shè)置為null即可。 Menu menu = new Menu(); menu.setId(1); menu.setName("新的名稱") menuRepository.updateById(menu); # 相當于SQL語句。update menu set name = "新的名稱" where id = 1;不是根據(jù)ID修改的怎么處理呢?把所有的按鈕設(shè)置為無效的。
Menu menu = new Menu(); menu.setStatus(false) udpate(menu, new EntityWrapper<Menu>().eq("type", 1)); # 相當于SQL語句。update menu set status = false where type = 1; -
查詢操作
根據(jù)ID查詢一個: Menu menu = this.selectById(1); 根據(jù)條件查詢一個 Menu menu = selectOne(new EntityWrapper<Menu>() .eq("type", 1).last("limit 1")); # last會造成SQL注入的風險。所以這個參數(shù)不能是外部傳入。 # lt("column",value) ==> column< value; # le("column",value) ==> column<= value; # gt("column",value) ==> column> value; # ge("column",value) ==> column>= value; # between(column, val1, val2) ==> columnbetween val1 and val2; # like(column,value) ==> like "%value%"; # orderBy(column, ture) ==> order By column asc ;false:表示倒序 # selectPage(page) ==> 分頁查詢 # selectPage(page, new Enw...) ==> 分頁查詢在家查詢條件。
當然也可以自己寫SQL語句。多表關(guān)聯(lián)查詢時,需要自己定義SQL。
和mybatis使用方式一致。
前端表單校驗
<template>
<div class="backdrop" v-loading="loading">
<div v-show="isList">
<el-row>
<el-col :span="10" :offset="1">
<el-input placeholder="請輸入內(nèi)容" clearable v-model="queryObj.value" class="input-with-select">
<el-select v-model="queryObj.type" slot="prepend" placeholder="請選擇">
<el-option label="名稱" value="name"></el-option>
<el-option label="路徑" value="path"></el-option>
</el-select>
<el-button slot="append" type="primary" icon="el-icon-search" @click="loadList"></el-button>
</el-input>
</el-col>
<el-col :span="6">
<el-button v-show="button.save" type="primary" @click="add" icon="el-icon-circle-plus-outline"
class="padding-button"></el-button>
<el-popover v-show="button.delete" placement="top" width="200" v-model="visible2">
<p>確定要刪除這些菜單嗎?</p>
<br/>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="primary" class="padding-button" @click="visible2 = false">取消
</el-button>
<el-button size="mini" type="danger" class="padding-button" @click="remove">確定</el-button>
</div>
<el-button slot="reference" type="danger" @click="visible2 = true" icon="el-icon-delete"
class="padding-button"></el-button>
</el-popover>
</el-col>
</el-row>
<div class="margin-bottom-10"></div>
<el-table :data="menuses" style="width: 100%" height="590" border
@sort-change="solrLoadMenusess"
@selection-change="electRow">
<!--多選框-->
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column sortable="custom" prop="id" label="ID" ></el-table-column>
<el-table-column sortable="custom" prop="name" label="名稱" ></el-table-column>
<el-table-column sortable="custom" prop="url" label="鏈接" ></el-table-column>
<el-table-column sortable="custom" prop="type" label="類型" >
<template slot-scope="scope">
<el-tag type="success" size="medium" v-if="scope.row.type == 1">菜單</el-tag>
<el-tag type="info" size="medium" v-if="scope.row.type == 2">按鈕</el-tag>
</template>
</el-table-column>
<el-table-column sortable="custom" prop="permission" label="權(quán)限" ></el-table-column>
<el-table-column label="操作" fixed="right" width="180">
<template slot-scope="scope">
<el-tooltip v-show="button.update" class="item" effect="dark" content="修改菜單" placement="top">
<el-button size="mini" type="primary" @click="update(scope.$index, scope.row)"
icon="el-icon-edit" circle></el-button>
</el-tooltip>
<el-tooltip v-show="button.delete" class="item" effect="dark" content="刪除菜單" placement="top">
<el-button size="mini" type="danger" @click="closeMenu(scope.$index, scope.row)"
icon="el-icon-delete" circle></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="pageSizeChange"
@current-change="currentPageChange"
:current-page="queryObj.currentPage"
:page-sizes="[10, 20, 30, 40]"
:page-size="queryObj.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="queryObj.total">
</el-pagination>
</div>
<div v-show="!isList">
<el-form ref="menu" :model="menu" :rules="rules" label-width="80px" label-position="right"
class="demo-ruleForm" size="mini">
<el-form-item prop="name" label="菜單名稱">
<el-col :span="10">
<el-input v-model="menu.name"></el-input>
</el-col>
</el-form-item>
<el-form-item prop="type" label="類型">
<el-col :span="3">
<el-select v-model="menu.type" placeholder="請選擇類型">
<el-option label="目錄" value="0"></el-option>
<el-option label="菜單" value="1"></el-option>
<el-option label="按鈕" value="2"></el-option>
</el-select>
</el-col>
</el-form-item>
<el-form-item prop="path" label="菜單路由" v-if="menu.type == 1">
<el-col :span="10">
<el-input v-model="menu.path"></el-input>
</el-col>
</el-form-item>
<el-form-item label="父級菜單">
<el-col :span="10">
<el-input v-model="menu.parentName" readonly @focus="dialogFormVisible = true"></el-input>
<el-dialog title="選擇父級菜單" width="30%"
:close-on-click-modal="false"
:close-on-press-escape="false"
:show-close="false"
:visible.sync="dialogFormVisible">
<el-tree
:data="this.buildMenus()"
@node-click="setParentId"
node-key="id"
:accordion=true
:highlight-current=true
:default-expanded-keys=[menu.parentId]
:current-node-key=menu.parentId
:props="{children: 'childs', label: 'name'}">
</el-tree>
<div slot="footer" class="dialog-footer">
<el-button @click="menu.parentId=0;menu.parentName='';dialogFormVisible = false;">取消
</el-button>
<el-button type="primary" @click="dialogFormVisible = false">確定</el-button>
</div>
</el-dialog>
</el-col>
</el-form-item>
<el-form-item prop="permission" label="菜單權(quán)限">
<el-col :span="10">
<el-input v-model="menu.permission"></el-input>
</el-col>
</el-form-item>
<el-form-item label="圖標">
<el-col :span="10">
<el-input v-model="menu.icon"></el-input>
</el-col>
</el-form-item>
<el-form-item>
<el-col :span="10">
<el-button type="primary" @click="submitMenu('menu')">提交</el-button>
<el-button @click="notSubmitMenu('menu')">取消</el-button>
</el-col>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
import {Menu} from "@/entity/Menu";
import {Query} from "@/utils/Query";
import {StringUtils} from "@/utils/StringUtils"
@Component({})
export default class MenuMana extends Vue {
# 表單校驗規(guī)則
rules: object = {
name: [ {required: true, message: '請輸入菜單名稱', trigger: 'blur'},
{min:2, max:5, message:"限制2~5個字符", trigger: 'blur'}
],
type: [{ required: true, message: '請選擇類型', trigger: 'change' }],
permission: [{ validator: (rule: any, value: any, callback: any)=> {
let _this:any = this.$refs["menu"];
if(_this.model.type == "2"){
if (value === "") {
callback(new Error("請輸入權(quán)限"));
}else {
callback();
}
}else {
callback();
}
}, trigger: 'change' }],
url: [{ required: true, message: '請輸入菜單路由', trigger: 'blur' }]
}
loading: boolean = false;
isList: boolean = true;
visible2: boolean = false;
dialogFormVisible: boolean = false;
menuses: Array<Menu> = [];
electMenus: Array<Menu> = [];
allMenus: Array<Menu> = [];
// 初始化菜單信息
menu: Menu = new Menu("", "1", "", "", "0", "");
button: object = {
save: StringUtils.isPermisson('sys:menu:save,sys:menu:select'),
update: StringUtils.isPermisson('sys:menu:update,sys:menu:select'),
delete: StringUtils.isPermisson('sys:menu:delete')
}
queryObj: Query = new Query();
mounted():void{
this.loadList();
this.allMenu().then(resp=>{
console.log("111111111")
});
}
// 加載列表數(shù)據(jù)
loadList():void {
const _this = this;
_this.loading = true;
_this.axios.get("/menu/list",{params: _this.queryObj})
.then(resp=> {
_this.loading = false;
_this.menuses = resp.data.records;
_this.queryObj.total = resp.data.total;
})
}
// 切換搜索條件
solrLoadMenusess(val: any):void{
this.queryObj.isAsc = val.order == "ascending";
this.queryObj.orderFields = val.prop;
this.loadList();
}
// 切換每頁數(shù)量
pageSizeChange(val: any):void{
this.queryObj.pageSize = val;
this.loadList();
}
// 切換頁面數(shù)
currentPageChange(val:any):void{
this.queryObj.currentPage = val;
this.loadList();
}
// 選中的值
electRow(val:any):void{
this.electMenus = val;
}
// ——
// 新增菜單
add():void{
this.isList = false;
this.menu = new Menu("", "1", "", "", "0", "");
}
// 修改菜單
update(index:number, row: Menu):void{
this.isList = false;
this.menu = new Menu("", "1", "", "", "0", "");
this.menu.id = row.id;
this.menu.name = row.name;
this.menu.parentId = row.parentId + "";
this.menu.url = row.url;
this.menu.permission = row.permission;
this.menu.type = row.type + "";
this.menu.icon = row.icon;
this.setMenuParentName();
}
// 設(shè)置當前菜單的父級菜單名字
setMenuParentName():void{
let parentName = "";
let id = this.menu.parentId;
this.allMenus.forEach(ele => {
if (ele.id.toString() == id) {
parentName = ele.parentName;
}else if (ele.childs != null) {
ele.childs.forEach(child=>{
if (child.id.toString() == id) {
parentName = child.parentName;
}
})
}
})
this.menu.parentName = parentName;
}
// 批量刪除
remove():void{
let _this = this;
_this.visible2 = false;
if (this.electMenus.length == 0) {
_this.$message.error("請選擇需要刪除的菜單");
return;
}
let arr = new Array<number>();
_this.axios.delete("/menu/delete",{data:arr})
.then(resp=>{
localStorage.removeItem("allMenus");
_this.$message.success("刪除成功了!");
if(_this.electMenus.length >= _this.menuses.length && _this.queryObj.currentPage > 1){
_this.queryObj.currentPage = _this.queryObj.currentPage - 1;
}
_this.loadList();
})
}
// 刪除單個
closeMenu(idnex:number, row: any):void{
let _this = this;
_this.$alert("確認刪除這個菜單嗎?", "友情提示", {
confirmButtonText: "確認",
callback: action => {
_this.axios.delete("/menu/delete",{data:[row.id]})
.then(resp=>{
localStorage.removeItem("allMenus");
_this.$message.success("刪除成功了!");
if(_this.menuses.length <= 1 && _this.queryObj.currentPage > 1){
_this.queryObj.currentPage = _this.queryObj.currentPage - 1;
}
_this.loadList();
})
}
})
}
// 提交
submitMenu(menu: string):void{
let _this = this;
let el: any = this.$refs[menu];
el.validate((valid: any) => {
if (valid) {
_this.loading = true;
if (_this.menu.id) {
_this.axios.put("/menu/update",_this.menu)
.then((resp: any) => {
_this.loading = false;
if (resp.code == 0){
_this.loading = false;
localStorage.removeItem("allMenus");
_this.$message.success("修改成功了!");
_this.loadList();
}
})
}else{
_this.axios.post("/menu/save",_this.menu)
.then((resp: any)=>{
_this.loading = false;
if(resp.code == 0) {
_this.isList = true;
localStorage.removeItem("allMenus");
_this.$message.success("添加成功了!")
_this.loadList();
};
})
}
}else{
this.$message.error("錯誤的提交");
return;
}
})
}
// 不提交菜單
notSubmitMenu(menu:string):void{
this.isList = true;
this.menu = new Menu("", "1", "", "", "0", "");
}
// 全部菜單
allMenu():Promise<any>{
let _this = this;
return new Promise(function (resolve, reject) {
let allMenus = localStorage.getItem("allMenus");
if (allMenus!=null && StringUtils.isNotBlank(allMenus)) {
_this.allMenus = JSON.parse(allMenus.toString());
if (_this.allMenus.length != 0) {
resolve(_this.allMenus);
}
}else{
_this.axios.get("/menu/select")
.then((resp: any)=>{
_this.allMenus = resp.data;
localStorage.setItem("allMenus", JSON.stringify(resp.data));
resolve(_this.allMenus);
})
}
});
}
// 處理菜單
buildMenus(): Array<Menu> {
let _this = this;
let arr = new Array<Menu>();
arr = _this.allMenus;
/*arr.forEach(elv=>{
if(elv.childs){
elv.childs.forEach((child:Menu)=>{
child.childs = new Array<Menu>();
})
}
})*/
return arr;
}
// 選擇父級菜單時,賦值
setParentId(data: Menu,node: any, eml:any): void{
this.menu.parentId = data.id.toString();
this.menu.parentName = data.name;
}
}
</script>
<style scoped>
.el-col{
margin-bottom: 10px;
margin-top: 10px;
}
</style>