欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot 圖書管理系統(tǒng)(刪除、強制登錄、更新圖書)詳細代碼

 更新時間:2024年09月28日 13:46:35   作者:昭著  
在企業(yè)開發(fā)中,通常不采用delete語句進行物理刪除,而是使用邏輯刪除,邏輯刪除通過修改標識字段來表示數(shù)據(jù)已被刪除,方便數(shù)據(jù)恢復,本文給大家介紹SpringBoot 圖書管理系統(tǒng)實例代碼,感興趣的朋友跟隨小編一起看看吧

一、刪除圖書

1.并不使用delete語句:

  • 原因:企業(yè)開發(fā)中,因為數(shù)據(jù)就意味著金錢,所以我們不會使用delete去刪除(delete刪除是物理刪除,找不回來那種)
  • delete使用場景:delete 語句通常在進行數(shù)據(jù)修復時才會使用,比如測試人員如果要進行測試,是需要手工造一些數(shù)據(jù)的。當測試完畢后,這些數(shù)據(jù)就是臟數(shù)據(jù)(假數(shù)據(jù))了,是沒有任何價值的,此時就可

2.以使用delete把數(shù)據(jù)刪掉

  • 刪除的分類:邏輯刪除 + 物理刪除
  • 物理刪除:直接把數(shù)據(jù)刪掉
  • 邏輯刪除:軟刪除/假刪除,通過字段的標識來表示這個數(shù)據(jù)被刪除了
    • 很多地方都在使用,比如軟件開發(fā)、硬盤刪除上
    • 刪除時不是說把這塊內(nèi)容給清空了,而是把標識改了,這也是我們可以找回的原因(再把標識改回來)
  • 物理刪除+存檔 或 邏輯刪除+存檔:
    • 什么是存檔:
      • 建一個和原表字段一致的表 ,如果原表要刪除一個數(shù)據(jù),就把這個數(shù)據(jù)移到存檔表里
      • 存檔表我們大多數(shù)情況不使用,查找時是從原表里查,當需要數(shù)據(jù)恢復時,才會從存檔表里查
    • 為什么都使用邏輯刪除了,還要使用存檔表:存檔表可以認為是一個流水表

3.刪除圖書功能的實現(xiàn)方法:因為我們此處我們使用邏輯刪除,所以沒必要搞一個deleteBook,沿用修改圖書的接口updateBook即可
4.代碼:由于后端代碼updateBook已經(jīng)實現(xiàn)了,所以此處只要寫前端代碼即可(把id傳過去,status固定為0)

function deleteBook(bookId){
    var isDelete = confirm("確認刪除?");
    if (isDelete){
        $.ajax({
            type: "post",
            url: "/book/updateBook",
            data: {
                id: bookId,
                status: 0  //接口設計中,0表示被刪除的
            },
            success: function (result){
                if (result == ""){
                    location = "book_list.html";
                }else{
                    alert(result);
                }
            }
        });
    }
}

二、批量刪除

1.思路解析:因為我們使用了邏輯刪除,所以批量刪除就等于批量更新,但我們不能像刪除單個圖書一樣,使用updateBook,因為此處我們需要更新多個,updateBook只能更新一個

2.后端代碼
Controller 層

  • @RequestParam:因為我們使用下面的方式發(fā)請求,參數(shù)是在查詢字符串上。且后端設置的接口是List,默認接收是用數(shù)組(如果使用的是數(shù)組,可以不加該注解),所以要使用@RequestParam
    • @RequestParam:請求參數(shù)是查詢字符串上的參數(shù)
    • @RequestBody:請求參數(shù)是body正文,需要把請求正文的內(nèi)容轉(zhuǎn)換為對象
    • @ResponseBody:返回的內(nèi)容是響應正文
  • @RequestParam:關(guān)于參數(shù)的設計
    • 我們可以使用各種方法去接收前端發(fā)來的參數(shù),可以設置參數(shù)在正文、url……里,接收的是數(shù)組、List、其他類……只要合乎邏輯,能完成需求即可

@RequestMapping("/batchDelete")
public String batchDeleteBook(@RequestParam List<Integer> ids){
    log.info("接收到的ids:{}", ids);
    Integer res = bookService.batchDeleteBook(ids);
    if (res <= 0){
        log.error("批量刪除失敗,ids:{}", ids);
        return "失敗";
    }
    return "";
}

Service 層

  • try-catch:bookInfo.batchDelete(ids)為【主邏輯方法】,但是代碼有可能會執(zhí)行失敗,所以要【try-catch】
  • 關(guān)于日志的打?。?ul>
  • 可以方便我們后續(xù)找錯,因為會有【需求沒有實現(xiàn) + 一條日志都沒有的情況】,如SQL正確運行了,但影響的行數(shù)為0
  • 此時如果要排除錯誤,就需要一點一點debug,十分麻煩。有了日志,可以快速定位是哪里有問題
public Integer batchDeleteBook(@RequestParam List<Integer> ids){
    Integer res = null;
    try{
        res = bookInfoMapper.batchDelete(ids);
    }catch (Exception e){
        log.error("批量刪除失敗, ids:{}", ids);
    }
    return res;
}

Mapper 層

  • 因為會涉及到動態(tài)SQL,為了方便,此處使用xml來編寫
Integer batchDelete(List<Integer> ids);
<update id="batchDelete">
    update book_info
    set status = 0
    where id in
    <foreach collection="ids" item="id" open="(" close=")" separator=",">
        #{id}
    </foreach>
</update>

3.前端代碼

  • input:checkbox:獲取所有的復選框
  • name=‘selectBook’:復選框有很多,此時我們要獲取名字為selectBook的
  • checked:表示已經(jīng)被選中的
  • each(function):對每一個選中的復選框進行某個操作
  • ids.push($(this).val()):把復選框的值放到ids這個數(shù)組里
function batchDelete(){
    var isDelete = confirm("確認批量刪除?");
    if (isDelete){
        var ids = [];
        $("input:checkbox[name='selectBook']:checked").each(function (){
            ids.push($(this).val());
        })
        $.ajax({
            type: "post",
            url: "/book/batchDelete?ids=" + ids,
            success:function (result){
                if (result == ""){
                    location.href = "book_list.html";
                }else{
                    alert(result);
                }
            }
        });
    }
}

三、強制登錄

3.1 不使用攔截器

  • 需求介紹:我們希望后端能檢查有無登錄,如果沒有登錄跳轉(zhuǎn)到登錄頁面的操作
  • 新增業(yè)務狀態(tài)碼和錯誤信息:
    • 業(yè)務狀態(tài)碼:用來表示后端是否正確響應了,和http狀態(tài)碼是兩個概念(業(yè)務狀態(tài)碼表示的是業(yè)務的情況,http狀態(tài)碼則是連接的情況,http請求成功才可能有業(yè)務狀態(tài)碼)
      • 案例:如果業(yè)務狀態(tài)碼表示成功,但是返回的數(shù)據(jù)為0,表示當前沒有數(shù)據(jù)。如果業(yè)務狀態(tài)碼表示失敗,數(shù)據(jù)也為0,此時就表示后端請求失敗了
      • 數(shù)字的定義:業(yè)務狀態(tài)碼由程序員自定義(什么數(shù)字是什么情況),不過,我們一般會把失敗定義為的數(shù),把成功定義為>0的數(shù)
      • 前端的情況:哪怕業(yè)務狀態(tài)碼返回的那個數(shù)字表示的是失敗,依舊是http成功連接的情況,前端走的是【success:funcation】,如果http狀態(tài)碼表示的是失敗,走的是【error:function】
  • 錯誤信息:根據(jù)code知道具體錯誤是什么,然后前端把這個具體錯誤反饋給用戶
@Data
public class PageResult<T> {
    private List<BookInfo> records;
    private Integer total;
    //此處設置0表示成功,-1為失敗
    private Integer code;
    //錯誤信息
    private String errMsg;
    private PageRequest request;
    public PageResult(List<BookInfo> records, Integer total, PageRequest request) {
        this.records = records;
        this.total = total;
        this.request = request;
    }
}

3.新增Result類

  • 原因:
    • 其他接口都需要強制登錄等統(tǒng)一操作,如果都寫在代碼里,要寫很多份,而且一旦要改需求,改動量大,耦合性太高
    • 故我們可以把之前的返回結(jié)果進行一個封裝,封裝為Result類,即每一個Controller接口返回的數(shù)據(jù)都是Result類,前端根據(jù)Result里的信息進行不同的反饋

  • 優(yōu)化tip ---->使用枚舉:
    • 原因:與其狀態(tài)碼這邊使用Integer,還不如使用枚舉,因為使用Integer還需要我們專門去查文檔來看各個數(shù)字的是什么意思
    • Getter 和 Setter:因為枚舉是不能用@Data的,所以此處我們要自己寫Getter和Setter方法
public enum ResultCode {
    SUCCESS(0),
    FAIL(-1),
    UNLOGIN(-2);
    private int code;
    ResultCode(int code) {
        this.code = code;
    }
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
}

4.提取Session

  • 原因:
    • 此時的Session是通過【session.setAttribute(“session_user_key”,userInfo)】存在【session_user_key】,但這依然有耦合性太高的可能性,而且是個【硬編碼問題】,所以我們可以把他提取為一個常量
    • 使用方法:

  • 其他:關(guān)于硬編碼問題 ----> 我們要避免字符串直接出現(xiàn)在代碼中
    • 如果這個常量在很多地方要用,那就提到一個專門用來放常量的類里
    • 如果這個常量,只在當前這個類中使用,也可以通過【private static final xxx = xxx】的提上去

提取成構(gòu)造函數(shù):

優(yōu)化tip:使用泛型Result<>

  • Obejct的時機:方法里我們用的是static,表示【靜態(tài)】,靜態(tài)的執(zhí)行時機是要比類早的,但是泛型是要類執(zhí)行了才能拿到類型是什么。所以當前最多給成員屬性設置為泛型,方法中還是要使用Object
  • 代碼:需要在方法里面再聲明一下
@Data
public class Result<T> {
    /**
     * 業(yè)務狀態(tài)碼
     */
    private ResultCode code;
    /**
     * 錯誤信息
     */
    private String errMsg;
    /**
     * 把所有的返回數(shù)據(jù)都塞到這里
     */
    private T data;
    /**
     * 成功時執(zhí)行的方法
     * @return
     */
    public static <T> Result<T> seccess(Object data){
        Result result = new Result();
        result.setCode(ResultCode.SUCCESS);
        result.setErrMsg("");
        result.setData(data);
        return result;
    }
    /**
     * 失敗時執(zhí)行的方法
     * 有錯誤,無數(shù)據(jù)
     * @param errMsg
     * @return
     */
    public static <T> Result<T> fail(String errMsg){
        Result result = new Result();
        result.setCode(ResultCode.FAIL);
        result.setErrMsg(errMsg);
        result.setData(null);
        return result;
    }
    /**
     * 失敗時執(zhí)行的方法
     * 有錯誤,有
     * @param data
     * @param errMsg
     * @return
     */
    public static <T> Result<T> fail(Object data, String errMsg){
        Result result = new Result();
        result.setCode(ResultCode.FAIL);
        result.setErrMsg(errMsg);
        result.setData(data);
        return result;
    }
    /**
     * 未登錄時執(zhí)行的方法
     * @return
     */
    public static <T> Result<T> unlogin(){
        Result result = new Result();
        result.setCode(ResultCode.UNLOGIN);
        result.setErrMsg("用戶未登錄");
        result.setData(null);
        return result;
    }
}

測試

  • 需要先登錄才能訪問到列表頁面
  • 如果已經(jīng)登陸了,但是修改sessionId的值,依舊需要重新登錄(找不到服務器里對應的session了)

3.2 使用攔截器

  • 關(guān)于寫法:寫法有很多,重點是實現(xiàn)需求
  • response.setStatus(401):設置返回的http狀態(tài)碼為401
    • 401:未認證登錄,或者提供的認證沒被認可
    • 業(yè)務狀態(tài)碼由開發(fā)人員自定義,http狀態(tài)碼其實也是由http開發(fā)人員自定義的,但現(xiàn)在這已經(jīng)成為了易總規(guī)范,大家都需要遵守
  • 后端代碼:
    • response.setStatus(401):設置返回的http狀態(tài)碼為401
      • 401:未認證登錄,或者提供的認證沒被認可
      • 業(yè)務狀態(tài)碼由開發(fā)人員自定義,http狀態(tài)碼其實也是由http開發(fā)人員自定義的,但現(xiàn)在這已經(jīng)成為了易總規(guī)范,大家都需要遵守
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("用戶登錄校驗開始");
        HttpSession session = request.getSession(false);
        if (session != null && session.getAttribute(Constants.SESSION_USER_KEY) != null){
            UserInfo userInfo = (UserInfo) session.getAttribute(Constants.SESSION_USER_KEY);
            if (userInfo != null && userInfo.getId() > 0){
                return true;
            }
        }
        response.setStatus(401);
        return false;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("目標方法執(zhí)行后");
    }
}
@Configuration
public class webConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/user/login");  //在執(zhí)行登錄操作時,不要攔截
    }
}

4. 前端代碼

如果前端出現(xiàn)了錯誤,可以一行行注掉代碼后,通過console.log打印日志來判斷錯誤在哪

//http連接失敗時執(zhí)行的方法
error: function (error) {
    console.log(error);
    if (error.status == 401) {
        console.log("401");
        location.href = "login.html";
    }
}

四、更新圖書

后端代碼
Controller層

@RequestMapping("/updateBook")
public String updateBook(BookInfo bookInfo){
    log.info("接收到的bookInfo:{}", bookInfo);
    Integer result = bookService.updateBook(bookInfo);
    if (result == 0){
        log.error("更新圖書失敗,請聯(lián)系管理員");
        return "失敗";
    }
    return "";
}

Service層

public Integer updateBook(BookInfo bookInfo){
    Integer res = 0;
    try{
        res = bookInfoMapper.updateBook(bookInfo);
    }catch (Exception e){
        log.error("更新圖書失敗,e:{}", e);
    }
    return res;
}

Mapper層

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.book_test.Mapper.BookInfoMapper">
    <update id="updateBook">
        update book_info
        <set>
            <if test="bookName != null">
                book_name = #{bookName},
            </if>
            <if test="author != null">
                author = #{author},
            </if>
            <if test="count != null">
                count = #{count},
            </if>
            <if test="price != null">
                price = #{price},
            </if>
            <if test="publish != null">
                publish = #{publish},
            </if>
            <if test="status != null">
                status = #{status}
            </if>
        </set>
        where id = #{id};
    </update>
</mapper>

前端代碼

<script>
    $.ajax({
        type: "get",
        url: "/book/queryBookInfoById" + location.search,
        success: function (book){
            if (book != null) {
                //頁面輸入框的填充
                $("#bookId").val(book.id);
                $("#bookName").val(book.bookName);
                $("#bookAuthor").val(book.author);
                $("#bookStock").val(book.count);
                $("#bookPrice").val(book.price);
                $("#bookPublisher").val(book.publish);
                $("#bookStatus").val(book.status)
            } else {
                alert("圖書不存在")
            }
        }
    });
    function update() {
        $.ajax({
            type: "post",
            url: "/book/updateBook",
            data: $("#updateBook").serialize(),
            success: function (result) {
                if (result != null) {
                    location.href = "book_list.html";
                } else {
                    alert(result);
                }
            }
        });
    }
</script>

到此這篇關(guān)于SpringBoot 圖書管理系統(tǒng)(刪除、強制登錄、更新圖書)詳細代碼的文章就介紹到這了,更多相關(guān)SpringBoot 圖書管理系統(tǒng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java字符串日期類Date和Calendar相互轉(zhuǎn)化及相關(guān)常用方法

    java字符串日期類Date和Calendar相互轉(zhuǎn)化及相關(guān)常用方法

    Java語言的Calendar(日歷),Date(日期),和DateFormat(日期格式)組成了Java標準的一個基本但是非常重要的部分,下面這篇文章主要給大家介紹了關(guān)于java字符串日期類Date和Calendar相互轉(zhuǎn)化及相關(guān)常用方法的相關(guān)資料,需要的朋友可以參考下
    2023-12-12
  • 如何將復雜SQL轉(zhuǎn)換成Java對象的實例講解

    如何將復雜SQL轉(zhuǎn)換成Java對象的實例講解

    轉(zhuǎn)換復雜SQL到Java代碼,我們需要確定數(shù)據(jù)庫連接方式和工具,使用JDBC的API來連接數(shù)據(jù)庫、執(zhí)行SQL語句,復雜SQL語句可以被拆分為多個步驟,每個步驟執(zhí)行一個特定的操作,通過將SQL語句拆分為多個步驟,我們可以更好地理解復雜SQL的邏輯,并且更容易將其轉(zhuǎn)換為Java代碼
    2024-05-05
  • JAVA面向?qū)ο笤O計寵物類方式

    JAVA面向?qū)ο笤O計寵物類方式

    本指南涉及JAVA面向?qū)ο蟮膶櫸镱愒O計,包括寵物類的父類及其子類小貓類和小狗類,用戶可以選擇養(yǎng)貓或養(yǎng)狗,給寵物起名字,實現(xiàn)喂食互動,同時寵物具有飽食度和快樂度屬性,適合初學者學習面向?qū)ο笤O計
    2024-10-10
  • 解決get請求入?yún)NotNull驗證不生效問題

    解決get請求入?yún)NotNull驗證不生效問題

    這篇文章主要介紹了解決get請求入?yún)NotNull驗證不生效問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot集成Swagger使用SpringSecurity控制訪問權(quán)限問題

    SpringBoot集成Swagger使用SpringSecurity控制訪問權(quán)限問題

    這篇文章主要介紹了SpringBoot集成Swagger使用SpringSecurity控制訪問權(quán)限問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • SpringBoot實現(xiàn)HTTP調(diào)用的7 種方式

    SpringBoot實現(xiàn)HTTP調(diào)用的7 種方式

    本文主要介紹了SpringBoot實現(xiàn)HTTP調(diào)用的7 種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-04-04
  • SpringMVC @GetMapping注解路徑?jīng)_突問題解決

    SpringMVC @GetMapping注解路徑?jīng)_突問題解決

    MD5對密碼進行加密存儲是常見的一種加密方式,本文主要介紹了Java雙重MD5加密實現(xiàn)安全登錄,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07
  • spring boot項目application.properties文件存放及使用介紹

    spring boot項目application.properties文件存放及使用介紹

    這篇文章主要介紹了spring boot項目application.properties文件存放及使用介紹,我們的application.properties文件中會有很多敏感信息,大家在使用過程中要多加小心
    2021-06-06
  • HttpMessageConverter報文信息轉(zhuǎn)換器的深入講解

    HttpMessageConverter報文信息轉(zhuǎn)換器的深入講解

    在Spring中內(nèi)置了大量的HttpMessageConverter,通過請求頭信息中的MIME類型,選擇相應的HttpMessageConverter,這篇文章主要給大家介紹了關(guān)于HttpMessageConverter報文信息轉(zhuǎn)換器的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • Java使用線程池執(zhí)行定時任務

    Java使用線程池執(zhí)行定時任務

    本文介紹了Java使用線程池執(zhí)行定時任務,其中ScheduledThreadPool和SingleThreadScheduledExecutor都是可以執(zhí)行定時任務的,但是具體怎么執(zhí)行,下面我們一起進入文章了解具體詳情吧
    2022-05-05

最新評論