若依【(前后端分離版)SpringBoot+Vue3】

文章目錄

  • 什么是若依
  • 使用若依
  • 驗證碼的前端實現
    • 📌 前后端驗證碼流程說明文檔
      • 1、前端初始化驗證碼
      • 2、前端界面顯示
      • 3、后端生成驗證碼接口(GET /captchaImage)
      • 4、用戶提交登錄信息
      • 5、后端驗證驗證碼邏輯(POST /login)
      • 6、登錄失敗處理(前端)
  • 新增崗位功能詳細解析
    • 一、前端實現流程
      • 1. 用戶觸發新增操作
      • 2. 初始化表單
      • 3. 表單結構
      • 4. 表單驗證規則
      • 5. 提交表單
    • 二、后端實現流程
      • 1. 控制器接收請求
      • 2. 唯一性校驗
      • 3. 數據插入實現
      • 4. 實體類驗證
    • 三、關鍵特性與設計思想
    • 四、完整數據流
  • 修改崗位功能詳細解析
    • 一、前端實現流程
      • 1. 修改按鈕觸發 (Post.vue)
      • 2. 處理修改操作 (Post.vue)
      • 3. 獲取崗位詳情API (post.js)
      • 4. 表單提交處理 (Post.vue)
      • 5. 修改崗位API (post.js)
    • 二、后端實現流程
      • 1. 控制器接收請求 (SysPostController.java)
      • 2. 服務層處理 (SysPostServiceImpl.java)
      • 3. 唯一性校驗邏輯 (SysPostServiceImpl.java)
      • 4. Mapper層SQL (SysPostMapper.xml)
    • 三、關鍵設計要點
  • 刪除崗位功能詳細解析
    • 一、前端實現流程
      • 1. 刪除觸發方式
      • 2. 刪除處理邏輯
      • 3. 關鍵處理步驟
    • 二、后端實現流程
      • 1. 控制器入口
      • 2. 服務層實現
      • 3. 關鍵業務邏輯
    • 三、安全與完整性設計
      • 1. 多級保護機制
      • 2. 外鍵約束建議(DDL示例)
    • 四、異常處理流程
      • 1. 業務異常處理
      • 2. 前端異常處理
    • 五、設計亮點分析
    • 六、完整工作流程
  • 查詢崗位功能詳細解析
    • 一、查詢功能分類
    • 二、分頁條件查詢(核心功能)
      • 1. 前端實現流程
      • 2. 后端實現流程
      • 3. 分頁機制
    • 三、導出查詢
      • 1. 前端實現
      • 2. 后端實現
    • 四、詳情查詢(單個崗位查詢)
      • 1. 前端實現
      • 2. 后端實現
    • 五、查詢功能設計亮點
    • 六、復雜查詢場景處理
      • 統計查詢
  • 崗位導出功能詳細解析
    • 一、前端實現流程
      • 1. 導出按鈕觸發
      • 2. 導出處理邏輯
      • 3. 下載方法封裝
    • 二、后端實現流程
      • 1. 控制器入口
      • 2. 實體類Excel注解


什么是若依

提示:這里可以添加本文要記錄的大概內容:

若依是開源項目,便于二次開發,百度直接搜索:若依官網

1、減少了自己的代碼量

2、學習優秀開源項目底層的編程思想,設計思路,提高自己的編程能力

使用若依

使用開源項目的步驟:

1、下載并運行
在這里插入圖片描述
啟動后端:
在這里插入圖片描述

啟動前端:VS CODE 插件GitHub Copilot ChatAgent模式下
在這里插入圖片描述

在這里插入圖片描述在這里插入圖片描述
項目成功啟動頁面:
在這里插入圖片描述

2、看懂業務流程

3、進行二次開發

驗證碼的前端實現

后端生成一個表達式

1+1=2
1+1=?@2

1+1=?轉成圖片,傳到前端展示,答案2存入Redis

輸入答案點擊登錄,就把表單存入后臺了,這時候從Redis中把正確答案拿出來,兩個答案對比

📌 前后端驗證碼流程說明文檔

1、前端初始化驗證碼

在 Vue 的 <script setup> 中,組件掛載時會調用 getCode() 函數初始化驗證碼。

getCode() 函數邏輯:

getCode().then(res => {captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabledif (captchaEnabled.value) {codeUrl.value = "data:image/gif;base64," + res.imgloginForm.value.uuid = res.uuid}
})
  • captchaEnabled.value:根據后端返回決定是否啟用驗證碼(默認啟用)
  • codeUrl.value:將 base64 圖片數據拼接為可直接顯示的 URL
  • loginForm.value.uuid:保存后端返回的驗證碼唯一標識(UUID)

2、前端界面顯示

在模板中通過 v-if="captchaEnabled" 控制驗證碼區域的顯示:

<el-form-item prop="code" v-if="captchaEnabled"><el-input v-model="loginForm.code" placeholder="驗證碼" /><div class="login-code"><img :src="codeUrl" @click="getCode" title="點擊刷新驗證碼" /></div>
</el-form-item>
  • 點擊圖片時重新調用 getCode(),刷新驗證碼
  • 用戶輸入驗證碼后,與 uuid 一起提交給后端

3、后端生成驗證碼接口(GET /captchaImage)

通過getCodeImg引入
在這里插入圖片描述

找到對應代碼:
在這里插入圖片描述
解釋:
定義一個名為 getCodeImg 的函數
request:這是封裝好的 Axios 請求函數,通常是項目中封裝的 HTTP 請求方法。
整個 request({ ... }) 是一個 HTTP 請求配置對象。
請求的后端接口地址是 /captchaImage

使用 HTTP 的 GET 方法發送請求,用于獲取數據

設置請求超時時間為 20 秒(20000 毫秒),如果 20 秒內沒有返回結果,請求將自動中斷,并進入 .catch() 分支。

在登錄頁F12
在這里插入圖片描述
在這里插入圖片描述

打開 request 文件
在這里插入圖片描述
創建一個 Axios 實例 service,用于發起 HTTP 請求
配置該實例的基礎 URL 為一個環境變量,實現環境自適應
設置請求超時時間為 10 秒,防止請求長時間掛起

值在配置文件中定義,配置文件:
在這里插入圖片描述
在這里插入圖片描述

4、用戶提交登錄信息

用戶點擊登錄時,前端調用 handleLogin() 提交數據:

userStore.login(loginForm.value)

提交內容包括:

  • username:用戶名
  • password:密碼
  • code:用戶輸入的驗證碼
  • uuid:當前驗證碼的唯一標識

5、后端驗證驗證碼邏輯(POST /login)

登錄請求:

export function login(username, password, code, uuid) {return request({url: '/login',method: 'post',data: { username, password, code, uuid }})
}

后端偽代碼邏輯:

function login(username, password, code, uuid) {// 1. 檢查是否啟用驗證碼if (captchaEnabled) {// 2. 從 Redis 獲取驗證碼String redisCode = redis.get(uuid);// 3. 驗證碼比對(忽略大小寫)if (!redisCode || !redisCode.equalsIgnoreCase(code)) {return error("驗證碼錯誤");}// 4. 刪除已使用的驗證碼redis.delete(uuid);}// 5. 繼續賬號密碼驗證...
}

6、登錄失敗處理(前端)

userStore.login(loginForm.value).catch(() => {loading.value = falseif (captchaEnabled.value) {getCode() // 登錄失敗時刷新驗證碼}
})
  • 登錄失敗時自動刷新驗證碼,防止暴力破解
  • 用戶點擊圖片也可手動刷新驗證碼

📋完整流程圖

getCodeImg()↓
調用 request()↓
發送 GET 請求到 /captchaImage↓
請求頭中設置 isToken = false(表示不需要 token)↓
等待響應(最多 20 秒)↓
返回 base64 圖片和 uuid

新增崗位功能詳細解析

新增功能是崗位管理系統的核心操作之一,涉及前后端協同工作。下面從用戶操作到數據存儲的完整流程進行詳細解析:

一、前端實現流程

1. 用戶觸發新增操作

<el-button type="primary" plain icon="Plus"@click="handleAdd"v-hasPermi="['system:post:add']"
>新增</el-button>
  • v-hasPermi指令校驗用戶是否有system:post:add權限
  • 點擊按鈕觸發handleAdd方法

2. 初始化表單

function handleAdd() {reset() // 重置表單數據open.value = true // 打開對話框title.value = "添加崗位" // 設置對話框標題
}function reset() {form.value = {postId: undefined,postCode: undefined,postName: undefined,postSort: 0,status: "0",remark: undefined}proxy.resetForm("postRef") // 重置表單驗證狀態
}
  • 初始化表單對象,設置默認值(如狀態默認為"0"正常)
  • 重置表單驗證狀態,清除之前的錯誤提示

3. 表單結構

<el-dialog :title="title" v-model="open" width="500px"><el-form ref="postRef" :model="form" :rules="rules" label-width="80px"><el-form-item label="崗位名稱" prop="postName"><el-input v-model="form.postName" placeholder="請輸入崗位名稱" /></el-form-item><el-form-item label="崗位編碼" prop="postCode"><el-input v-model="form.postCode" placeholder="請輸入編碼名稱" /></el-form-item><!-- 其他字段... --></el-form>
</el-dialog>
  • 使用el-dialog組件實現模態對話框
  • el-form綁定表單數據和驗證規則

4. 表單驗證規則

const rules = {postName: [{ required: true, message: "崗位名稱不能為空", trigger: "blur" }],postCode: [{ required: true, message: "崗位編碼不能為空", trigger: "blur" }],postSort: [{ required: true, message: "崗位順序不能為空", trigger: "blur" }],
}
  • 定義字段級驗證規則
  • required標記必填字段
  • trigger: 'blur'表示失去焦點時觸發驗證

5. 提交表單

function submitForm() {proxy.$refs["postRef"].validate(valid => {if (valid) {addPost(form.value).then(response => {proxy.$modal.msgSuccess("新增成功")open.value = false // 關閉對話框getList() // 刷新列表})}})
}
  1. 觸發表單驗證
  2. 驗證通過后調用addPost API
  3. 顯示操作成功提示
  4. 關閉對話框并刷新崗位列表

二、后端實現流程

1. 控制器接收請求

@PostMapping
@PreAuthorize("@ss.hasPermi('system:post:add')")
@Log(title = "崗位管理", businessType = BusinessType.INSERT)
public AjaxResult add(@Validated @RequestBody SysPost post) {// 唯一性校驗if (!postService.checkPostNameUnique(post)) {return error("新增崗位'" + post.getPostName() + "'失敗,崗位名稱已存在");} else if (!postService.checkPostCodeUnique(post)) {return error("新增崗位'" + post.getPostName() + "'失敗,崗位編碼已存在");}// 設置創建人post.setCreateBy(getUsername());// 執行插入return toAjax(postService.insertPost(post));
}
  • @PostMapping處理POST請求
  • @PreAuthorize校驗用戶權限
  • @Log記錄操作日志(類型為INSERT)
  • @Validated觸發實體類字段驗證
  • @RequestBody接收JSON格式的崗位數據

2. 唯一性校驗

// 校驗崗位名稱唯一性@Overridepublic boolean checkPostNameUnique(SysPost post) {Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();SysPost info = postMapper.checkPostNameUnique(post.getPostName());if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) {return UserConstants.NOT_UNIQUE;}return UserConstants.UNIQUE;}// Mapper查詢
@Select("select * from sys_post where post_name = #{postName} limit 1")
SysPost checkPostNameUnique(String postName);
  • 查詢數據庫是否存在相同崗位名稱
  • 排除當前崗位自身(更新時使用)
  • 同樣邏輯校驗崗位編碼唯一性

3. 數據插入實現

// 服務層
public int insertPost(SysPost post) {return postMapper.insertPost(post);
}// Mapper XML
<insert id="insertPost" parameterType="SysPost" useGeneratedKeys="true" keyProperty="postId">insert into sys_post(<if test="postId != null and postId != 0">post_id,</if><if test="postCode != null and postCode != ''">post_code,</if><if test="postName != null and postName != ''">post_name,</if><if test="postSort != null">post_sort,</if><if test="status != null and status != ''">status,</if><if test="remark != null and remark != ''">remark,</if><if test="createBy != null and createBy != ''">create_by,</if>create_time)values(<if test="postId != null and postId != 0">#{postId},</if><if test="postCode != null and postCode != ''">#{postCode},</if><if test="postName != null and postName != ''">#{postName},</if><if test="postSort != null">#{postSort},</if><if test="status != null and status != ''">#{status},</if><if test="remark != null and remark != ''">#{remark},</if><if test="createBy != null and createBy != ''">#{createBy},</if>sysdate())
</insert>
  • 動態生成SQL語句
  • useGeneratedKeys="true"獲取自增主鍵
  • 自動填充創建時間和創建人
  • 只插入非空字段,提高靈活性

4. 實體類驗證

public class SysPost extends BaseEntity {/*** 崗位編碼*/@Excel(name = "崗位編碼")private String postCode;/*** 崗位名稱*/@Excel(name = "崗位名稱")private String postName;/*** 崗位排序*/@Excel(name = "崗位排序")private Integer postSort;// 其他字段
}
  • @NotBlank驗證非空字符串
  • @Size限制字符串長度
  • @NotNull確保數值字段不為空
  • 驗證失敗自動返回錯誤信息給前端

三、關鍵特性與設計思想

  1. 多層驗證機制

    • 前端:Element Plus表單驗證
    • 網絡層:JSON格式校驗
    • 后端:JSR-303實體驗證
    • 業務層:唯一性校驗
    • 數據庫:唯一約束(需在DDL中定義)
  2. 操作審計

    • 通過@Log注解自動記錄:
     @Log(title = "崗位管理", businessType = BusinessType.INSERT)
  1. 安全控制

    • 權限校驗:@PreAuthorize("@ss.hasPermi('system:post:add')"
    • 數據隔離:自動注入當前用戶getUsername()
  2. 響應式設計

    • 前端:提交后自動刷新列表
    • 后端:返回標準化的AjaxResult對象
  3. 異常處理

    • 唯一性沖突返回可讀性錯誤信息
    • 數據庫操作異常全局處理

四、完整數據流

  1. 用戶點擊"新增"按鈕
  2. 前端打開對話框并重置表單
  3. 用戶填寫表單并提交
  4. 前端進行字段級驗證
  5. 驗證通過后調用/system/post POST API
  6. 后端控制器接收請求:
    • 權限校驗
    • 實體字段驗證
    • 業務規則校驗(唯一性)
  7. 服務層設置創建人
  8. Mapper執行動態SQL插入
  9. 返回操作結果(成功/失敗)
  10. 前端提示結果并刷新列表

這種設計實現了前后端分離架構下的高效協作,通過多層驗證保證數據質量,利用注解簡化開發,同時確保系統的安全性和可維護性。

修改崗位功能詳細解析

我將詳細講解崗位管理模塊中的修改功能,從前端到后端的完整實現流程。修改功能是CRUD操作中的重要環節,涉及數據加載、校驗、更新等多個關鍵步驟。

一、前端實現流程

1. 修改按鈕觸發 (Post.vue)

<el-table-column label="操作" align="center" class-name="small-padding fixed-width"><template #default="scope"><el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:post:edit']">修改</el-button></template>
</el-table-column>
  • 在表格操作列中放置修改按鈕
  • 使用v-hasPermi指令進行權限控制
  • 點擊時調用handleUpdate方法并傳入當前行數據

2. 處理修改操作 (Post.vue)

// 修改按鈕操作
function handleUpdate(row) {reset(); // 重置表單狀態const postId = row.postId; // 獲取當前崗位IDgetPost(postId).then(response => {form.value = response.data; // 填充表單數據open.value = true; // 打開對話框title.value = "修改崗位"; // 設置對話框標題});
}

執行流程:

  1. 重置表單狀態,確保無殘留數據
  2. 從行數據中獲取崗位ID
  3. 調用API獲取崗位詳細信息
  4. 將返回數據填充到表單
  5. 打開對話框并設置標題

3. 獲取崗位詳情API (post.js)

// 查詢崗位詳細
export function getPost(postId) {return request({url: '/system/post/' + postId,method: 'get'})
}
  • 向后臺發送GET請求
  • URL格式:/system/post/{postId}
  • 獲取指定ID的崗位詳情

4. 表單提交處理 (Post.vue)

// 提交按鈕
function submitForm() {proxy.$refs["postRef"].validate(valid => {if (valid) {if (form.value.postId != undefined) {// 修改操作updatePost(form.value).then(response => {proxy.$modal.msgSuccess("修改成功");open.value = false; // 關閉對話框getList(); // 刷新列表})} else {// 新增操作...}}});
}
  • 先進行表單驗證
  • 根據postId判斷是修改還是新增
  • 調用updatePostAPI提交修改
  • 成功后關閉對話框并刷新列表

5. 修改崗位API (post.js)

// 修改崗位
export function updatePost(data) {return request({url: '/system/post',method: 'put',data: data})
}
  • 使用HTTP PUT方法
  • 將整個表單數據作為請求體發送
  • URL為/system/post

二、后端實現流程

1. 控制器接收請求 (SysPostController.java)

@PreAuthorize("@ss.hasPermi('system:post:edit')")
@Log(title = "崗位管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysPost post) {// 唯一性校驗if (!postService.checkPostNameUnique(post)) {return error("修改崗位'" + post.getPostName() + "'失敗,崗位名稱已存在");} else if (!postService.checkPostCodeUnique(post)) {return error("修改崗位'" + post.getPostName() + "'失敗,崗位編碼已存在");}// 設置更新人post.setUpdateBy(getUsername());// 執行更新return toAjax(postService.updatePost(post));
}

執行流程:

  1. @PreAuthorize進行權限校驗
  2. @Log記錄操作日志
  3. @Validated進行參數校驗(基于JSR-303)
  4. 校驗崗位名稱和編碼的唯一性
  5. 設置更新人(當前登錄用戶)
  6. 調用服務層執行更新

2. 服務層處理 (SysPostServiceImpl.java)

@Override
public int updatePost(SysPost post) {return postMapper.updatePost(post);
}
  • 直接調用Mapper層執行更新
  • 返回影響行數

3. 唯一性校驗邏輯 (SysPostServiceImpl.java)

@Override
public boolean checkPostNameUnique(SysPost post) {Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();SysPost info = postMapper.checkPostNameUnique(post.getPostName());if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue()) {return UserConstants.NOT_UNIQUE;}return UserConstants.UNIQUE;
}

校驗邏輯:

  1. 獲取當前崗位ID(修改時為真實ID,新增時為null)
  2. 查詢數據庫是否存在相同名稱的崗位
  3. 如果存在同名崗位:
    • 且ID不同:表示是其他崗位的同名,返回不唯一
    • 且ID相同:表示是自身,允許更新

4. Mapper層SQL (SysPostMapper.xml)

<update id="updatePost" parameterType="SysPost">update sys_post<set><if test="postCode != null and postCode != ''">post_code = #{postCode},</if><if test="postName != null and postName != ''">post_name = #{postName},</if><if test="postSort != null">post_sort = #{postSort},</if><if test="status != null and status != ''">status = #{status},</if><if test="remark != null">remark = #{remark},</if><if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>update_time = sysdate()</set>where post_id = #{postId}
</update>

SQL特點:

  1. 使用動態SQL(<set><if>標簽)
  2. 只更新非空字段
  3. 自動設置更新時間
  4. 使用數據庫函數設置時間(sysdate())
  5. 根據postId定位記錄

三、關鍵設計要點

  1. 權限控制雙重保障

    • 前端:v-hasPermi指令控制按鈕顯示
    • 后端:@PreAuthorize注解進行方法級權限校驗
  2. 數據一致性保證

    • 唯一性校驗:防止名稱/編碼重復
    • 事務管理:確保更新操作的原子性
  3. 審計字段自動化

    • 自動記錄更新人:post.setUpdateBy(getUsername())
    • 自動更新時間:update_time = sysdate()
  4. 前后端校驗結合

    • 前端:Element Plus表單校驗
    • 后端:JSR-303參數校驗 + 業務邏輯校驗
  5. 性能優化

    • 動態SQL:只更新變化的字段
    • 最小化數據傳輸:前端只發送必要字段
  6. 用戶體驗優化

    • 修改前加載完整數據
    • 操作成功自動刷新列表
    • 明確的錯誤提示信息

刪除崗位功能詳細解析

刪除功能是崗位管理系統中最敏感的操作之一,需要特別關注數據完整性和安全控制。下面從前后端協同角度深入解析刪除功能的實現:

一、前端實現流程

1. 刪除觸發方式

前端支持兩種刪除模式:

<!-- 單個刪除(行內操作) -->
<el-table-column label="操作"><template #default="scope"><el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:post:remove']">刪除</el-button></template>
</el-table-column><!-- 批量刪除(頂部操作欄) -->
<el-buttontype="danger"plainicon="Delete":disabled="multiple"@click="handleDelete"v-hasPermi="['system:post:remove']"
>刪除</el-button>

2. 刪除處理邏輯

function handleDelete(row) {// 獲取待刪除的崗位IDconst postIds = row.postId || ids.value;// 確認對話框proxy.$modal.confirm('是否確認刪除崗位編號為"' + postIds + '"的數據項?').then(function() {// 調用刪除APIreturn delPost(postIds);}).then(() => {// 刪除成功后刷新列表getList();proxy.$modal.msgSuccess("刪除成功");}).catch(() => {// 用戶取消操作});
}

3. 關鍵處理步驟

  1. 獲取刪除目標
    • 單個刪除:從行數據獲取row.postId
    • 批量刪除:從選中的ids數組中獲取多個ID
   const postIds = row.postId || ids.value;
  1. 二次確認

    • 使用$modal.confirm顯示確認對話框
    • 明確顯示將被刪除的崗位編號
  2. API調用

    • 調用delPost方法發送刪除請求
    • 支持單個ID或ID數組(自動處理)
  3. 結果反饋

    • 成功:顯示"刪除成功"提示
    • 失敗:全局異常處理(已在底層封裝)
  4. 狀態更新

    • 刷新崗位列表數據
    • 重置選中狀態

二、后端實現流程

1. 控制器入口

@PreAuthorize("@ss.hasPermi('system:post:remove')")
@Log(title = "崗位管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{postIds}")
public AjaxResult remove(@PathVariable Long[] postIds) {return toAjax(postService.deletePostByIds(postIds));
}
  • @DeleteMapping:處理DELETE請求
  • @PathVariable:獲取URL路徑中的崗位ID數組
  • @PreAuthorize:權限校驗(需system:post:remove權限)
  • @Log:記錄操作日志(類型為DELETE)

2. 服務層實現

@Override
public int deletePostByIds(Long[] postIds) {// 1. 檢查崗位是否被用戶使用for (Long postId : postIds) {SysPost post = selectPostById(postId);if (countUserPostById(postId) > 0) {throw new ServiceException(String.format("%1$s已分配,不能刪除", post.getPostName()));}}// 2. 執行批量刪除return postMapper.deletePostByIds(postIds);
}

3. 關鍵業務邏輯

  1. 使用狀態檢查
   // 查詢崗位用戶關聯數量public int countUserPostById(Long postId) {return userPostMapper.countUserPostById(postId);}// SysUserPostMapper.xml<select id="countUserPostById" resultType="int">SELECT COUNT(1) FROM sys_user_post WHERE post_id = #{postId}</select>
  1. 安全刪除機制

    • 遍歷每個待刪除崗位
    • 檢查sys_user_post關聯表
    • 如果存在關聯用戶,拋出業務異常
    • 包含崗位名稱的友好錯誤提示
  2. 批量刪除執行

   <delete id="deletePostByIds" parameterType="Long">DELETE FROM sys_post WHERE post_id IN<foreach collection="array" item="postId" open="(" separator="," close=")">#{postId}</foreach></delete>
  • 使用MyBatis的<foreach>處理ID數組
  • 生成DELETE FROM sys_post WHERE post_id IN (1,2,3)語句

三、安全與完整性設計

1. 多級保護機制

層級保護措施目的
前端v-hasPermi指令控制按鈕顯示
網絡JWT令牌驗證身份認證
應用@PreAuthorize注解方法級權限控制
數據關聯檢查防止誤刪使用中的崗位
數據庫外鍵約束最終數據保護

2. 外鍵約束建議(DDL示例)

CREATE TABLE sys_user_post (user_id BIGINT NOT NULL,post_id BIGINT NOT NULL,PRIMARY KEY (user_id, post_id),FOREIGN KEY (post_id) REFERENCES sys_post(post_id)ON DELETE RESTRICT  -- 阻止刪除被引用的崗位
);

四、異常處理流程

1. 業務異常處理

// 服務層拋出異常
if (countUserPostById(postId) > 0) {throw new ServiceException(String.format("%1$s已分配,不能刪除", post.getPostName()));
}// 全局異常處理器
@ExceptionHandler(ServiceException.class)
public AjaxResult handleServiceException(ServiceException e) {return AjaxResult.error(e.getMessage());
}
  • 返回HTTP 200狀態碼(前端能處理的業務異常)
  • 錯誤信息格式:{ code: 500, msg: "崗位已分配,不能刪除" }

2. 前端異常處理

// post.js API封裝
export function delPost(postId) {return request({url: '/system/post/' + postId,method: 'delete'})
}// 全局響應攔截器
service.interceptors.response.use(response => {const res = response.data;if (res.code !== 200) {// 顯示后端返回的錯誤信息Message.error(res.msg || 'Error');return Promise.reject(new Error(res.msg || 'Error'));}return res;},error => {// 處理HTTP錯誤(如401, 500等)}
);

五、設計亮點分析

  1. 批量操作優化

    • 單次數據庫交互完成批量刪除(IN語句)
    • 減少數據庫連接開銷
  2. 用戶友好設計

    • 明確提示哪個崗位無法刪除
    • 二次確認避免誤操作
    • 批量選擇狀態自動管理
  3. 事務完整性

   @Transactional(rollbackFor = Exception.class)public int deletePostByIds(Long[] postIds) {// 操作在同一個事務中}
  • 整個刪除操作原子性執行
  • 檢查與刪除要么全成功,要么全回滾
  1. 前后端協作
    • RESTful風格API:DELETE /system/post/{ids}
    • 統一的ID傳遞格式(數組自動轉換)
    • 標準化的響應格式(AjaxResult)

六、完整工作流程

  1. 前端操作

    • 用戶選擇單個/多個崗位
    • 點擊刪除按鈕
    • 確認刪除提示
  2. 請求發送

   DELETE /system/post/12,34,56Authorization: Bearer xxxx
  1. 后端處理

    • 權限驗證(@PreAuthorize)
    • 日志記錄(@Log)
    • 遍歷檢查每個崗位使用狀態
    • 執行批量刪除SQL
    • 返回操作結果
  2. 結果反饋

    • 成功:{ code: 200, msg: "操作成功" }
    • 失敗:{ code: 500, msg: "經理崗位已分配,不能刪除" }
  3. 前端響應

    • 顯示操作結果提示
    • 刷新崗位列表
    • 重置選中狀態

這種設計確保了刪除操作的安全性、完整性和用戶體驗,通過多層校驗防止數據誤刪,同時提供清晰的反饋幫助用戶理解操作結果。

查詢崗位功能詳細解析

我將詳細講解崗位管理模塊中的各種查詢功能,包括分頁查詢、條件過濾、詳情查詢和下拉框查詢等。查詢功能是系統的核心基礎功能,設計良好的查詢機制能極大提升用戶體驗。

一、查詢功能分類

查詢類型前端調用方法后端接口主要用途
分頁條件查詢listPost(query)GET /system/post/list管理頁面主列表展示
導出查詢同分頁查詢POST /system/post/exportExcel導出功能
詳情查詢getPost(postId)GET /system/post/{postId}查看/修改單個崗位詳情
下拉框查詢optionselect()GET /system/post/optionselect用戶管理中的崗位選擇下拉框

二、分頁條件查詢(核心功能)

1. 前端實現流程

頁面組件 (Post.vue)

<template><!-- 搜索表單 --><el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch"><el-form-item label="崗位編碼" prop="postCode"><el-inputv-model="queryParams.postCode"placeholder="請輸入崗位編碼"clearablestyle="width: 200px"@keyup.enter="handleQuery"/></el-form-item><el-form-item><el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button><el-button icon="Refresh" @click="resetQuery">重置</el-button></el-form-item></el-form><!-- 數據表格 --><el-table :data="postList" v-loading="loading"><!-- 表格列定義 --><el-table-column label="崗位編碼" align="center" prop="postCode" /></el-table><!-- 分頁組件 --><pagination :total="total" v-model:page="queryParams.pageNum"v-model:limit="queryParams.pageSize"@pagination="getList"/>
</template><script setup>
import { listPost } from "@/api/system/post";// 查詢參數
const queryParams = reactive({pageNum: 1,      // 當前頁碼pageSize: 10,     // 每頁條數postCode: "",     // 崗位編碼條件postName: "",     // 崗位名稱條件status: ""        // 狀態條件
});// 崗位列表數據
const postList = ref([]);
// 總記錄數
const total = ref(0);
// 加載狀態
const loading = ref(true);// 獲取崗位列表
function getList() {loading.value = true;listPost(queryParams).then(response => {postList.value = response.rows;  // 當前頁數據total.value = response.total;    // 總記錄數loading.value = false;});
}// 處理搜索
function handleQuery() {queryParams.pageNum = 1;  // 重置到第一頁getList();
}// 初始化加載數據
getList();
</script>

2. 后端實現流程

Controller層 (SysPostController.java)

@PreAuthorize("@ss.hasPermi('system:post:list')")
@GetMapping("/list")
public TableDataInfo list(SysPost post) {// 1. 啟動分頁startPage();  // 2. 查詢數據List<SysPost> list = postService.selectPostList(post);// 3. 封裝分頁結果return getDataTable(list);
}

Service層 (SysPostServiceImpl.java)

@Override
public List<SysPost> selectPostList(SysPost post) {return postMapper.selectPostList(post);
}

Mapper XML (SysPostMapper.xml)

<select id="selectPostList" parameterType="SysPost" resultMap="SysPostResult">SELECT post_id, post_code, post_name, post_sort, status, create_timeFROM sys_post<where><if test="postCode != null and postCode != ''">AND post_code LIKE CONCAT('%', #{postCode}, '%')</if><if test="postName != null and postName != ''">AND post_name LIKE CONCAT('%', #{postName}, '%')</if><if test="status != null and status != ''">AND status = #{status}</if></where>ORDER BY post_sort ASC
</select>

3. 分頁機制

分頁關鍵點

  1. startPage()方法從請求參數中解析pageNumpageSize
  2. PageHelper自動改寫SQL添加分頁語句
  3. 分頁信息存儲在ThreadLocal中
  4. 查詢結束后自動獲取總記錄數

三、導出查詢

1. 前端實現

function handleExport() {proxy.download("system/post/export", {...queryParams.value}, `post_${new Date().getTime()}.xlsx`);
}

2. 后端實現

@Log(title = "崗位管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:post:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysPost post) {// 1. 查詢所有符合條件的數據(不分頁)List<SysPost> list = postService.selectPostList(post);// 2. 使用Excel工具類導出ExcelUtil<SysPost> util = new ExcelUtil<>(SysPost.class);util.exportExcel(response, list, "崗位數據");
}

特點

  • 復用相同的查詢邏輯selectPostList
  • 不分頁查詢所有數據
  • 使用ExcelUtil工具類簡化導出
  • 自動將實體字段映射到Excel列

四、詳情查詢(單個崗位查詢)

1. 前端實現

// 查詢崗位詳細
function handleUpdate(row) {const postId = row.postId;getPost(postId).then(response => {form.value = response.data;open.value = true;});
}// API方法
export function getPost(postId) {return request({url: '/system/post/' + postId,method: 'get'})
}

2. 后端實現

@PreAuthorize("@ss.hasPermi('system:post:query')")
@GetMapping(value = "/{postId}")
public AjaxResult getInfo(@PathVariable Long postId) {return success(postService.selectPostById(postId));
}// Service實現
@Override
public SysPost selectPostById(Long postId) {return postMapper.selectPostById(postId);
}// Mapper XML
<select id="selectPostById" parameterType="Long" resultMap="SysPostResult">SELECT * FROM sys_post WHERE post_id = #{postId}
</select>

五、查詢功能設計亮點

  1. 統一查詢邏輯復用

    • 分頁查詢和導出查詢共用同一套查詢邏輯
    • 避免代碼重復,保證數據一致性
  2. 靈活的條件組合

   SELECT * FROM sys_postWHERE 1=1/* 動態添加條件 */AND post_code LIKE '%DEV%'AND status = '0'ORDER BY post_sort ASC
  • 使用MyBatis動態SQL
  • 支持多條件自由組合
  1. 安全的分頁機制

    • 最大分頁限制(配置文件設置)
    • 防止惡意請求大量數據
  2. 響應式前端設計

   <el-table v-loading="loading" :data="postList"><el-table-column label="狀態"><template #default="scope"><dict-tag :options="sys_normal_disable" :value="scope.row.status"/></template></el-table-column></el-table>
  • 加載狀態提示
  • 字典值自動轉換
  • 分頁組件與表格聯動
  1. 完善的權限控制
   // 列表查詢權限@PreAuthorize("@ss.hasPermi('system:post:list')")// 導出權限@PreAuthorize("@ss.hasPermi('system:post:export')")// 詳情查看權限@PreAuthorize("@ss.hasPermi('system:post:query')")

六、復雜查詢場景處理

統計查詢

// 統計崗位使用人數
@Override
public int countUserPostById(Long postId) {return userPostMapper.countUserPostById(postId);
}// Mapper
<select id="countUserPostById" resultType="int">SELECT COUNT(1) FROM sys_user_post WHERE post_id = #{postId}
</select>

崗位導出功能詳細解析

導出功能是崗位管理系統的重要特性,允許用戶將查詢結果導出為Excel文件。下面從技術實現角度深入分析導出功能的完整流程:

一、前端實現流程

1. 導出按鈕觸發

<el-buttontype="warning"plainicon="Download"@click="handleExport"v-hasPermi="['system:post:export']"
>導出</el-button>
  • v-hasPermi指令校驗導出權限
  • 點擊觸發handleExport方法

2. 導出處理邏輯

function handleExport() {// 調用封裝的下載方法proxy.download("system/post/export", {...queryParams.value  // 攜帶當前查詢條件}, `post_${new Date().getTime()}.xlsx`); // 生成帶時間戳的文件名
}

3. 下載方法封裝

// @/utils/request.js 在post.js內找:import request from '@/utils/request'
// 通用下載方法
export function download(url, params, filename, config) {downloadLoadingInstance = ElLoading.service({ text: "正在下載數據,請稍候", background: "rgba(0, 0, 0, 0.7)", })return service.post(url, params, {transformRequest: [(params) => { return tansParams(params) }],headers: { 'Content-Type': 'application/x-www-form-urlencoded' },responseType: 'blob',...config}).then(async (data) => {const isBlob = blobValidate(data)if (isBlob) {const blob = new Blob([data])saveAs(blob, filename)} else {const resText = await data.text()const rspObj = JSON.parse(resText)const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']ElMessage.error(errMsg)}downloadLoadingInstance.close()}).catch((r) => {console.error(r)ElMessage.error('下載文件出現錯誤,請聯系管理員!')downloadLoadingInstance.close()})
}

二、后端實現流程

1. 控制器入口

@Log(title = "崗位管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:post:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysPost post) {// 查詢所有符合條件的崗位List<SysPost> list = postService.selectPostList(post);// 使用Excel工具類導出ExcelUtil<SysPost> util = new ExcelUtil<>(SysPost.class);util.exportExcel(response, list, "崗位數據");
}

2. 實體類Excel注解

public class SysPost extends BaseEntity {@Excel(name = "崗位序號", cellType = ColumnType.NUMERIC)private Long postId;@Excel(name = "崗位編碼")private String postCode;@Excel(name = "崗位名稱")private String postName;@Excel(name = "崗位排序", cellType = ColumnType.NUMERIC)private Integer postSort;@Excel(name = "狀態", readConverterExp = "0=正常,1=停用")private String status;
}

導出功能通過前后端協同實現,后端負責數據處理和Excel生成,前端負責文件下載。合理的設計可以支持從幾百條到數百萬條數據的導出需求,同時保證系統的穩定性和安全性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/916671.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/916671.shtml
英文地址,請注明出處:http://en.pswp.cn/news/916671.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Ubuntu24安裝MariaDB/MySQL后不知道root密碼如何解決

Ubuntu 24.04 安裝 MariaDB 后 root 密碼未知&#xff1f;解決方案在此在 Ubuntu 24.04 上新安裝 MariaDB 后&#xff0c;許多用戶會發現自己不知道 root 用戶的密碼&#xff0c;甚至在安裝過程中也沒有提示設置密碼。這是因為在較新的 MariaDB 版本中&#xff0c;默認情況下 r…

Cloudflare CDN 中設置地域限制并返回特定界面

文章目錄 什么是CDN 什么是Cloudflare 注冊Cloudflare 賬號,添加域名、修改DNS并激活郵箱 阻止或允許特定國家或地區訪問 常見規則表達式 WAF自定義規則 + 自定義錯誤頁面 使用Workers腳本 什么是CDN CDN 是一種優化網站請求處理的機制。它是在用戶訪問網站 (服務器) 時用戶與…

Ubuntu高頻實用命令大全

Ubuntu系統中高頻實用命令 以下為Ubuntu系統中高頻實用命令的分類整理,涵蓋系統管理、文件操作、網絡配置等場景,每個命令附帶簡要說明: 系統信息與管理 uname -a 顯示系統內核版本、主機名等詳細信息。 lsb_release -a 查看Ubuntu發行版版本信息。 uptime 顯示系統運行時…

關于C#的編程基礎:數據類型與變量全解析

一.基本的數據類型 1.什么是數據類型 在編程語言中&#xff0c;數據類型&#xff08;Data Type&#xff09; 是對變量存儲的 “數據的種類” 的定義&#xff0c;它決定了&#xff1a; 變量可以存儲哪些值&#xff08;例如整數、文本、布爾值&#xff09;。這些值在內存中如何…

深入解析 Spring 獲取 XML 驗證模式的過程

關鍵要點Spring 的 XML 驗證模式&#xff1a;Spring 框架在加載 XML 配置文件時&#xff0c;會根據文件內容判斷使用 DTD&#xff08;文檔類型定義&#xff09;或 XSD&#xff08;XML 模式定義&#xff09;進行驗證。自動檢測機制&#xff1a;Spring 默認使用自動檢測&#xff…

復現《Local GDP Estimates Around the World》論文的完整指南

復現《Local GDP Estimates Around the World》論文的完整指南 1. 引言 1.1 論文概述 《Local GDP Estimates Around the World》是一篇重要的經濟地理學研究論文&#xff0c;作者提出了一種創新的方法來估計全球范圍內次國家層面的GDP數據。這項工作填補了全球經濟發展研究中子…

Sql注入 之sqlmap使用教程

一、安裝sqlmap 瀏覽器訪問SQLmap官網 即可下載工具&#xff1b;需要說明的是&#xff0c;SQLmap運行依賴于python環境&#xff0c;所以在下載使用前務必在電腦及終端上安裝好python環境。 通過網盤分享的文件&#xff1a;sqlmap-master.zip鏈接: https://pan.baidu.com/s/1YZi…

安寶特案例丨戶外通信機房施工革新:AR+作業流技術破解行業難題

在數字化浪潮席卷各行各業的今天&#xff0c;傳統戶外通信機房建設領域正經歷一場靜悄悄的變革。作為信息社會的“神經樞紐”&#xff0c;戶外機房的質量直接關系到通信網絡的穩定性&#xff0c;但長期以來&#xff0c;這一領域卻深受施工標準化不足、質量管控難、驗收追溯復雜…

在 CentOS 中安裝 MySQL 的過程與問題解決方案

MySQL 是一款廣泛使用的開源關系型數據庫管理系統&#xff0c;在 CentOS 系統中安裝 MySQL 是很多開發者和運維人員常做的工作。下面將詳細介紹安裝過程以及可能遇到的問題和解決方案。 一、安裝前的準備工作 在安裝 MySQL 之前&#xff0c;需要做好一些準備工作&#xff0c;…

阿里 Qwen3 四模型齊發,字節 Coze 全面開源,GPT-5 8 月初發布!| AI Weekly 7.21-7.27

&#x1f4e2;本周AI快訊 | 1分鐘速覽&#x1f680;1?? &#x1f9e0; 阿里 Qwen3 全系列爆發 &#xff1a;一周內密集發布四款新模型&#xff0c;包括 Qwen3-235B-A22B-Thinking-2507、Qwen3-Coder 和 Qwen3-MT&#xff0c;MMLU-Pro 成績超越 Claude Opus 4&#xff0c;百萬…

C語言第 9 天學習筆記:數組(二維數組與字符數組)

C語言第09天學習筆記&#xff1a;數組&#xff08;二維數組與字符數組&#xff09; 內容提要 數組 二維數組字符數組二維數組 定義 二維數組本質上是一個行列式組合&#xff0c;由行和列兩部分組成&#xff0c;屬于多維數組&#xff0c;通過行和列解讀&#xff08;先行后列&…

使用OpenCV做個圖片校正工具

昨天有位兄臺給我發了個文件&#xff0c;是下面這個樣子的&#xff1a;那一雙小腳既沒有裹成三寸金蓮&#xff0c;又沒有黑絲&#xff0c;這圖片肯定不符合我的要求。我要的是這個樣子的好不好&#xff1a;讓他拿掃描儀重新給我規規矩矩掃一個發過來&#xff1f;他要能用掃描儀…

《不只是接口:GraphQL與RESTful的本質差異》

RESTful API憑借其與HTTP協議的天然融合&#xff0c;以資源為核心的架構理念&#xff0c;在過去十余年里構建了Web數據交互的基本秩序&#xff1b;而GraphQL的出現&#xff0c;以“按需獲取”為核心的查詢模式&#xff0c;打破了傳統的請求-響應邏輯&#xff0c;重新定義了前端…

博士招生 | 香港大學 招收人工智能和網絡安全方向 博士生

學校簡介香港大學創立于 1911 年&#xff0c;是香港歷史最悠久的高等學府&#xff0c;QS 2025 世界排名第 17 位。計算機科學學科在 QS 2025 學科排名中位列全球第 31 位、亞洲第 5 位。計算機系&#xff08;Department of Computer Science&#xff09;下設系統、人工智能、數…

Linux知識回顧總結----基礎IO

目錄 1. 理解“文件” 1.1 文件的定義 2. 回顧 C 語言的文件操作 2.1 文件操作 2.2 實現cat 2.3 可以實現打印的幾種方式 3. 系統文件的IO 3.2 使用系統的接口 3.3 內部的實現 3.4 重定向 4. 文件系統的內核結構 5. 緩沖區 5.1 是什么 5.2 為什么 5.3 有什么 5.4 見見…

網絡:基礎概念

網絡&#xff1a;基礎概念 在計算機發展過程中&#xff0c;最開始每個計算機時相互獨立的&#xff0c;后來人們需要用計算機合作處理任務&#xff0c;這就牽扯到了數據交換&#xff0c;所以最開始的網絡就誕生了。一開始&#xff0c;網絡都是局域網LAN&#xff0c;后來技術成熟…

圖像識別邊緣算法

文章目錄1. 基本概念2. 邊緣檢測原理邊緣類型&#xff1a;3. 常見邊緣檢測算法3.1 Sobel算子3.2 Canny邊緣檢測3.3 Laplacian算子4. Canny邊緣檢測詳細流程流程圖示例&#xff1a;詳細步驟說明&#xff1a;5. 邊緣檢測算法比較6. 參數調優建議Canny邊緣檢測參數&#xff1a;Sob…

【Java Web實戰】從零到一打造企業級網上購書網站系統 | 完整開發實錄(終)

&#x1f9ea; 測試與質量保證 &#x1f50d; 全方位測試體系 我建立了企業級的全方位測試體系來確保系統質量&#xff1a; &#x1f9ea; 測試金字塔模型 #mermaid-svg-u4I8UuUAyxJVjcqs {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill…

QT開發---網絡編程下

HTTP協議 HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本傳輸協議&#xff09;是互聯網上應用最為廣泛的協議之一&#xff0c;用于客戶端和服務器之間的通信。默認端口80&#xff0c;傳輸層使用的是TCP協議特點無連接&#xff1a;HTTP協議是無連接的&#xff…

mac 蘋果電腦 Intel 芯片(Mac X86) 安卓虛擬機 Android模擬器 的救命稻草(下載安裝指南)

引言&#xff1a; 還在為你的Intel芯片MacBook&#xff08;i5, i7, i9等&#xff09;找不到合適的安卓虛擬機而發愁嗎&#xff1f;隨著Apple Silicon (M1/M2/M3) 芯片的普及&#xff0c;大量優秀的安卓模擬器&#xff08;如Android Studio自帶的模擬器、網易MuMu等&#xff09;…