瑞吉外賣實戰專案全攻略——第三天
該系列將記錄一份完整的實戰專案的完成程序,該篇屬于第三天
案例來自B站黑馬程式員Java專案實戰《瑞吉外賣》,請結合課程資料閱讀以下內容
該篇我們將完成以下內容:
-
公共欄位自動填充
-
新添分類
-
分類資訊分頁查詢
-
洗掉分類
-
修改分類
公共欄位自動填充
我們的功能開發一般分為三個階段
需求分析
前面我們已經完成了后臺系統的員工系統的開發,在新增或修改員工時需要填寫創建時間創建人修改時間修改人等繁雜資訊
而且這些屬性基本在后續的菜品,套餐中都有所體現,我們把這些欄位稱為公共欄位,所以我們希望采用一種統一的方法來設定:
- MyBatisPlus為我們提供了公共欄位自動填充的功能
我們先來簡單介紹一下流程:
- 首先在我們需要修改的欄位屬性上添加注解:
// 屬性包括有INSERT,UPDATE,INSERT_UPDATE
@TableField(fill = FieldFill.屬性)
- 按照框架書寫元資料物件處理器,在此類中統一為公共欄位設定值,需要實作MetaObjectHandler介面
package com.qiuluo.reggie.common;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
// 記得設定為配置類
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 添加時自動設定
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
}
/**
* 修改時自動設定
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
}
}
代碼實作
首先我們為物體類的待修改屬性添加上注解:
package com.qiuluo.reggie.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String username;
private String name;
private String password;
private String phone;
private String sex;
private String idNumber;
private Integer status;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
在common檔案夾下創建新的MyMetaObjectHandler處理器:
package com.qiuluo.reggie.common;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 添加時自動設定
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
log.info("修改元資料");
// 我們可以在這里統一設定公共欄位的值
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime", LocalDateTime.now());
// 但是關于修改或創建人我們無法設定,因為我們無法得知目前是誰修改,這里暫時用Long(1)代替
metaObject.setValue("createUser", new Long(1));
metaObject.setValue("updateUser", new Long(1));
}
/**
* 修改時自動設定
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("updateUser", new Long(1));
}
}
之后,再將我們的服務層中相關設定屬性代碼去掉即可
功能完善
在上面我們已經完成基本的公共欄位的設定,但是我們會注意到我們無法設定相關人的資訊
因為我們在之前的服務層中采用Request來獲得當前Session下的保存的員工id,但目前我們無法獲得Request
但是我們可以采用執行緒的單一性來獲得當前執行緒下存盤的內容
每次客戶端發送的每次http請求,對應的服務器都會分配一個新的執行緒來處理,在處理程序中設計到下面類方法都屬于一個相同的執行緒:
- LoginCheckFilter的doFilter方法
- EmployeeController的update方法
- MyMetaObjectHandler的updateFill方法
驗證方法可以采用獲得并比較當前執行緒:
// 通過該方法獲得當前執行緒的id
long id = Thread.currentThread().getId();
// 以日志的形式輸出即可
log.info("當前執行緒id:" + id);
正常情況下我們會得到三個執行緒相同的id
那么我們就可以利用執行緒相同的原理,在當前執行緒中直接存盤id,再在MyMetaObjectHandler中獲得id
我們主要采用ThreadLocal,我們簡單介紹一下ThreadLocal:
- ThreadLocal并不是一-個Thread,而是Thread的區域變數,
- 當使用ThreadLocal維護變數時,每個使用該變數的執行緒具有獨立的變數副本,
- 每一個執行緒都可以獨立地改變自己的副本,而不會影響其它執行緒所對應的副本,
- ThreadLocal為每個執行緒提供單獨一份存盤空間,具有執行緒隔離的效果,只有在執行緒內才能獲取到對應的值,執行緒外則不能訪問,
其中Thread Local主要只有兩個方法:
// 設定當前執行緒的執行緒區域變數的值
public void set(T value);
// 回傳當前執行緒所對應的區域變數的值
public T get();
下面我們演示相關步驟:
- 設定一個工具類,用于使用當前執行緒的方法
package com.qiuluo.reggie.common;
/**
* 基于ThreadLocal的工具類,用于保存用戶id
*/
public class BaseContext {
// 設定一個ThreadLocal,存盤Long型(id)
private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
// 存盤方法,呼叫set
public static void setCurrentId(Long id){
threadLocal.set(id);
}
// 獲得方法,呼叫get
public static Long getCurrentId(){
return threadLocal.get();
}
}
- 在LoginCheckFilter的doFilter中獲得用戶id,并set儲存
package com.qiuluo.reggie.filter;
import com.alibaba.fastjson.JSON;
import com.qiuluo.reggie.common.BaseContext;
import com.qiuluo.reggie.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 檢查用戶是否已經完成登錄
*/
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter{
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String requestURI = request.getRequestURI();
log.info("攔截到請求:{}",requestURI);
String[] urls = new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**"
};
boolean check = check(urls, requestURI);
if(check){
log.info("本次請求{}不需要處理",requestURI);
filterChain.doFilter(request,response);
return;
}
if(request.getSession().getAttribute("employee") != null){
log.info("用戶已登錄,用戶id為:{}",request.getSession().getAttribute("employee"));
log.info("執行緒id" + Thread.currentThread().getId());
// 注意這里:我們直接使用工具類的方法來設定執行緒區域變數
Long empId = (Long) request.getSession().getAttribute("employee");
BaseContext.setCurrentId(empId);
filterChain.doFilter(request,response);
return;
}
log.info("用戶未登錄");
response.getWriter().write(JSON.toJSONString(Result.error("NOTLOGIN")));
return;
}
public boolean check(String[] urls,String requestURI){
for (String url : urls) {
boolean match = PATH_MATCHER.match(url, requestURI);
if(match){
return true;
}
}
return false;
}
}
- 在MyMetaObjectHandler的updateFill方法中獲得用戶id,并加載進相關屬性
package com.qiuluo.reggie.common;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 添加時自動設定
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
log.info("修改元資料");
log.info("執行緒id" + Thread.currentThread().getId());
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime", LocalDateTime.now());
// 我們呼叫工具類方法來使用ThreadLocal獲得當前id并賦值
metaObject.setValue("createUser", BaseContext.getCurrentId());
metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
/**
* 修改時自動設定
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
}
實際測驗
測驗方法很簡單,我們直接在主頁中點擊新建或修改方法,到資料庫內部查看修改時間或修改人即可
新增分類
我們的功能開發一般分為三個階段
需求分析
根據需求,我們需要設定分類管理資訊
分類資訊存放在一張表中,分為為菜品分類和套餐分類,我們用資料庫的type屬性來區分兩種分類
我們來到前端,分別點擊菜品分類和套餐分類的創建,F12查看傳輸資料就會發現:

點擊菜品分類,這里不僅傳輸了我們頁面書寫的name和sort,還額外傳遞了type屬性表示是菜品分類
因而我們只需要將資料傳入即可,不用分心設定是菜品分類還是套餐分類,直接書寫代碼即可
代碼實作
因為是新的物體類,我們需要重新構造一系列domain,mapper等內容
- 物體類
package com.qiuluo.reggie.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 分類
*/
@Data
public class Category implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//型別 1 菜品分類 2 套餐分類
private Integer type;
//分類名稱
private String name;
//順序
private Integer sort;
//創建時間
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
//更新時間
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
//創建人
@TableField(fill = FieldFill.INSERT)
private Long createUser;
//修改人
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
- 資料層
package com.qiuluo.reggie.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qiuluo.reggie.domain.Category;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface CategoryMapper extends BaseMapper<Category> {
}
- 業務層介面
package com.qiuluo.reggie.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Category;
public interface CategoryService extends IService<Category> {
}
- 業務層實作類
package com.qiuluo.reggie.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qiuluo.reggie.common.CustomException;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Category;
import com.qiuluo.reggie.domain.Dish;
import com.qiuluo.reggie.domain.Setmeal;
import com.qiuluo.reggie.mapper.CategoryMapper;
import com.qiuluo.reggie.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
}
- 服務層并書寫方法
package com.qiuluo.reggie.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Category;
import com.qiuluo.reggie.service.impl.CategoryServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@Slf4j
@RestController
@RequestMapping("/category")
public class CategoryController {
// 自動裝配
@Autowired
private CategoryServiceImpl categoryService;
// 查看前端url請求,為post型別,后面沒有跟網頁設定
@PostMapping
public Result<String> save(@RequestBody Category category){
// 創建時間/人,修改時間/人均已統一設定,我們只需要將資料保存進資料庫即可
categoryService.save(category);
return Result.success("新增成功");
}
}
實際測驗
來到主頁面,新添后去資料庫查看相關資訊即可
分類資訊分頁查詢
我們的功能開發一般分為三個階段
需求分析
我們需要將資料展現到網頁中,同時防止資料過多擁擠,我們采用分頁查詢的方法給出資料:

我們在之前的員工分類中已經完成了分頁插件的創建,所以這次我們只需要重繪頁面查看url以及資料即可:

直接實作相關代碼即可
代碼實作
我們直接在CategoryController中實作方法即可:
package com.qiuluo.reggie.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Category;
import com.qiuluo.reggie.service.impl.CategoryServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@Slf4j
@RestController
@RequestMapping("/category")
public class CategoryController {
@Autowired
private CategoryServiceImpl categoryService;
/**
* 分頁方法
*/
@GetMapping("/page")
public Result<Page> page(int page,int pageSize){
// 創建Page,并載入引數
Page pageImpl = new Page(page,pageSize);
categoryService.page(pageImpl);
// 我們不需要做匹配,但是我們需要按照sort的數值比對來進行排列,所以依舊需要創建LambdaQueryWrapper匹配器
LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByAsc(Category::getSort);
// 呼叫分頁方法
categoryService.page(pageImpl,queryWrapper);
// 資料回傳
return Result.success(pageImpl);
}
}
實際測驗
我們直接打開頁面,重繪頁面,有資料出現即可
洗掉分類
我們的功能開發一般分為三個階段
需求分析
我們點擊頁面后,可以查看后面有一個洗掉操作,點擊后我們會洗掉該套餐:

但是請注意當當前套餐中有相關菜品時,我們如果洗掉,那么菜品將無法顯示,所以我們還需要設定條件當該套餐中出現菜品時無法洗掉

我們的套餐中的菜品資訊并非存盤在套餐資料庫中,而是存盤在Dish和Setmeal資料表中:

所以我們需要創建這兩者的基本資訊,并在Category的業務層中修改默認代碼,創建一個符合我們要求的方法
代碼實作
首先我們將創建Dish和Setmeal的基本資訊,下面不做配置,這里僅作簡單羅列(和之前配置完全相同):
- Dish-Setmeal的實作類
- Dish-Setmeal的資料層
- Dish-Setmeal的業務層介面
- Dish-Setmeal的業務層
- Dish-Setmeal的服務層
接下來我們來介紹代碼的正式實作:
- 首先去資料庫業務層介面定義我們需要實作的方法介面:
package com.qiuluo.reggie.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Category;
public interface CategoryService extends IService<Category> {
// 書寫我們需要的方法
public Result<String> remove(Long id);
}
- 再去資料庫業務層實作我們定義的方法:
package com.qiuluo.reggie.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qiuluo.reggie.common.CustomException;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Category;
import com.qiuluo.reggie.domain.Dish;
import com.qiuluo.reggie.domain.Setmeal;
import com.qiuluo.reggie.mapper.CategoryMapper;
import com.qiuluo.reggie.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
// 我們需要使用到DishServiceImpl,SetmealServiceImpl來查詢是否有菜品相連,自動裝配即可
@Autowired
private DishServiceImpl dishService;
@Autowired
private SetmealServiceImpl setmealService;
// 實作方法
public Result<String> remove(Long id){
// 判斷是否有菜品相連
LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();
dishLambdaQueryWrapper.eq(Dish::getCategoryId,id);
int count1 = dishService.count(dishLambdaQueryWrapper);
if (count1 > 0){
// 如果有菜品相連,我們先拋出業務例外,這里暫時不實作,我們在后面實作
}
// 判斷是否有套餐相連
LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId,id);
int count2 = setmealService.count(setmealLambdaQueryWrapper);
if (count2 > 0){
// 如果有套餐相連,我們先拋出業務例外,這里暫時不實作,我們在后面實作
}
// 均無相連,采用父類的根據id洗掉方法,并回傳成功資訊
super.removeById(id);
return Result.success("成功洗掉");
}
}
- 我們在前面拋出了業務例外,我們去定義一個自定義例外:
package com.qiuluo.reggie.common;
/**
* 自定義業務例外類
* 注意:自定義例外都需要繼承RuntimeException
*/
public class CustomException extends RuntimeException{
public CustomException(String message){
super(message);
}
}
- 去我們的總的例外處理器中添加處理該例外的方法:
package com.qiuluo.reggie.common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.sql.SQLIntegrityConstraintViolationException;
/**
* 全域例外處理
* @ControllerAdvice 來書寫需要修改例外的注解類(該類中包含以下注解)
* @ResponseBody 因為回傳資料為JSON資料,需要進行格式轉換
*/
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
/**
* 處理例外
* @ExceptionHandler 來書寫需要修改的例外
* @return
*/
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public Result<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){
log.error(ex.getMessage());
if (ex.getMessage().contains("Duplicate entry")){
String[] split = ex.getMessage().split(" ");
String msg = split[2] + "已存在";
return Result.error(msg);
}
return Result.error("未知錯誤");
}
/**
* 處理自定義例外
* @ExceptionHandler 來書寫需要修改的例外
* @return
*/
@ExceptionHandler(CustomException.class)
public Result<String> CustomExceptionHandler(CustomException ex){
// 我們直接獲得例外中攜帶的資訊并回傳即可
log.error(ex.getMessage());
return Result.error(ex.getMessage());
}
}
- 回到業務層相對應位置拋出例外
package com.qiuluo.reggie.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qiuluo.reggie.common.CustomException;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Category;
import com.qiuluo.reggie.domain.Dish;
import com.qiuluo.reggie.domain.Setmeal;
import com.qiuluo.reggie.mapper.CategoryMapper;
import com.qiuluo.reggie.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
@Autowired
private DishServiceImpl dishService;
@Autowired
private SetmealServiceImpl setmealService;
// 實作方法
public Result<String> remove(Long id){
// 判斷是否有菜品相連
LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();
dishLambdaQueryWrapper.eq(Dish::getCategoryId,id);
int count1 = dishService.count(dishLambdaQueryWrapper);
if (count1 > 0){
// 拋出業務例外
throw new CustomException("已有菜品關聯,無法洗掉!");
}
// 判斷是否有套餐相連
LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId,id);
int count2 = setmealService.count(setmealLambdaQueryWrapper);
if (count2 > 0){
// 拋出業務例外
throw new CustomException("已有套餐關聯,無法洗掉!");
}
super.removeById(id);
return Result.success("成功洗掉");
}
}
- 最后我們到服務層實作該介面
package com.qiuluo.reggie.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Category;
import com.qiuluo.reggie.service.impl.CategoryServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@Slf4j
@RestController
@RequestMapping("/category")
public class CategoryController {
@Autowired
private CategoryServiceImpl categoryService;
// 這里需要注意:前端傳來的id名稱為ids(資料中帶有的),引數搞錯了是無法匹配的
@DeleteMapping
public Result<String> delete(Long ids){
categoryService.remove(ids);
return Result.success("洗掉成功");
}
}
實際測驗
回到主頁面,點擊一個自己創建的分類的洗掉鍵,分類消失
回到主頁面,點擊一個系統創建的分類的洗掉鍵,分類存在并彈出彈框顯示已有關聯無法洗掉
修改分類
我們的功能開發一般分為三個階段
需求分析
我們打開修改界面,點擊修改后查看相關url以及引數即可
url如下:

引數如下:

我們會發現修改分類實際是根據id來修改分類,其中傳遞的引數實際上是一個Category實作類
那么我們直接書寫代碼即可
代碼實作
我們直接在服務層書寫代碼:
package com.qiuluo.reggie.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Category;
import com.qiuluo.reggie.service.impl.CategoryServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@Slf4j
@RestController
@RequestMapping("/category")
public class CategoryController {
@Autowired
private CategoryServiceImpl categoryService;
@PutMapping
public Result<String> update(@RequestBody Category category){
categoryService.updateById(category);
return Result.success("修改成功");
}
}
實際測驗
我們直接回到主頁面,點擊修改,來到后臺查看資料實作即可
易錯點
在這里我們會點出該專案目前容易出錯的位置
工具類的使用
在公共欄位自動填充的部分,我們為了使用ThreadLocal從而創建了相對的工具類
我們的工具類就是為了便捷操作而使用的,我們為了使用相關的引數但同時多次不用創建物體而直接使用工具類
例如我們的ThreadLocal的工具類中:
package com.qiuluo.reggie.common;
// 我們直接創建了物體threadLocal,那么我們呼叫該物體時就不用多次創建物體
// 同時我們給出了該物體的封裝方法并設定為靜態方法,那么我們就可以直接呼叫該工具類的靜態方法來實作物體的方法
public class BaseContext {
private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
public static void setCurrentId(Long id){
threadLocal.set(id);
}
public static Long getCurrentId(){
return threadLocal.get();
}
}
例外處理
我們平時遇到的例外都是產生錯誤由系統拋出的例外
只有真實的專案中我們才會需要創建自己定義的例外,難點在于例外的創建格式以及將例外加入例外處理器中
首先我們需要創建自定義例外:
package com.qiuluo.reggie.common;
/**
* 自定義業務例外類
* 注意:一定要繼承RuntimeException
* 繼承RuntimeException之后我們才能直接拋出該例外
*/
public class CustomException extends RuntimeException{
// 內部直接書寫一個構造方法,因為我們拋出例外時都是直接new一個新的例外(手動書寫)
public CustomException(String message){
// 存盤一個簡單的反饋資訊
super(message);
}
}
再之后我們需要將該例外加入到例外處理器中:
package com.qiuluo.reggie.common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.sql.SQLIntegrityConstraintViolationException;
/**
* 全域例外處理
* @ControllerAdvice 來書寫需要修改例外的注解類(該類中包含以下注解)
* @ResponseBody 因為回傳資料為JSON資料,需要進行格式轉換
*/
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
/**
* 處理自定義例外
* @ExceptionHandler 來書寫需要修改的例外
* @return
*/
@ExceptionHandler(CustomException.class)
public Result<String> CustomExceptionHandler(CustomException ex){
// 我們不需要做過多處理,我們只是將大部分需要拋出例外的部分整合起來在這里統一處理
return Result.error(ex.getMessage());
}
}
結束語
該篇內容到這里就結束了,希望能為你帶來幫助~
附錄
該文章屬于學習內容,具體參考B站黑馬程式員的Java專案實戰《瑞吉外賣》
這里附上視頻鏈接:業務開發Day3-01-本章內容介紹_嗶哩嗶哩_bilibili
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/518795.html
標籤:Java
上一篇:golang中的變數陰影
