一、數據庫設計
CREATE TABLE `miaosha_user` ( `id` bigint(20) NOT NULL COMMENT '用戶ID,手機號碼', `nickname` varchar(255) NOT NULL, `password` varchar(32) DEFAULT NULL COMMENT 'MD5(MD5(pass明文+固定salt) salt)', `salt` varchar(10) DEFAULT NULL, `head` varchar(128) DEFAULT NULL COMMENT '頭像,雲存儲的ID', `register_date` datetime DEFAULT NULL COMMENT '注冊時間', `last_login_date` datetime DEFAULT NULL COMMENT '上登錄時間', `login_count` int(11) DEFAULT '0' COMMENT '登錄次數', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='秒殺用戶表'; SET FOREIGN_KEY_CHECKS = 1;
二、明文密碼兩次MD5處理
1、用戶端:pass = MD5(明文+固定salt)
2、服務端:pass = MD5(用戶輸入+隨機salt)
第一次加密防止用戶明文密碼在網絡上傳輸,第二次加密防止數據庫被盜后將一次加密反向破解
引入依賴commons-codec和commons-lang3,使用commons-codec依賴下的DigestUtils類的md5Hex方法加密處理
安全起見,使用固定salt(就是一個字符串)中的部分字符與密碼拼接后進行第一次加密
第二次加密使用隨機salt,通過入參salt來傳遞
三、JSR303參數檢驗+全局異常處理器
jsr303參數校驗
1、pom.xml 引入依賴spring-boot-starter-validation,該依賴包含了hibernate-validator依賴
2、LoginController.java 刪除之前的參數校驗部分,在doLogin方法的LoginVo類型入參前加上@Valid注解,該注解在validation-api依賴下,然而該依賴並沒有手動引入,可能是新建SpringBoot項目時自動引入了。
3、LoginVo.java 在password變量前添加@NotNull注解,@Length注解;在mobile變量前添加@NotNull注解,@IsMobile注解,其中@NotNull和@Length在validation-api依賴下,@IsMobile注解為接下來要自定義的注解。
4、IsMobile.java 新建注解,拷貝@NotNull注解中的部分內容,仿照着@NotNull注解來寫。在拷貝過來的@Constraint(validateBy={})中添加將要新建的IsMobileValidator.class類,做為校驗器,改完之后為@Constraint(validateBy={IsMobileValidator.class})。添加boolean required() default true; 表示標注該注解的變量必需要傳值。
5、IsMobileValidator.class 新建類,作為校驗器,需要實現ConstraintValidator<A, T>接口,A處就填IsMobile,T處填了String。實現父接口中的兩個方法,initialize和isValid方法。
6、運行測試,瀏覽器檢查代碼的Netword部分會提示需要的信息和異常信息。異常信息需要捕獲,需要的信息才可以正常提示,見下節。
異常處理
標題:異常處理
1、GlobalExceptionHandler.java 新建類,添加exceptionHandler方法,該方法需標注@ExceptionHandler(value = Exception.class) 表示要攔截所有的異常,方法體內先攔截剛才的BindException,步驟依次為異常類型強轉,獲取所有錯誤信息,拿到第一個錯誤,拿到具體錯誤信息,最后拼接完后返回。拼接調用接下來的CodeMsg.java類中的fillArgs方法。
2、CodeMsg.java 添加綁定異常靜態常量BIND_ERROR,注意他的msg參數處留一個位置。添加fillArgs方法,供第一步拼接時調用。
寫在最后:這樣,瀏覽器中的異常信息,經過上述代碼就可以捕獲並處理,最終友好的顯示在瀏覽器頁面。
標題:異常處理優化
0、導語:之前MiaoshaUserService.java類中login方法的返回值為CodeMsg類型,但是應該返回表達業務方法含義的方法,而不應該是CodeMsg類型。所以我們可以定義一個全局異常類,將異常直接拋出去,交給異常處理器處理。
1、GlobalException.java 新建異常類,封裝CodeMsg類型變量,供拋出時實例化使用。
2、MiaoshaUserService.java 修改login方法返回類型為boolean,方法體內的錯誤直接通過實例化GlobalException類,並入參CodeMsg類型的靜態常量,來將異常拋出去。
3、GlobalExceptionHandler.java 修改exceptionHandler方法,增加處理GlobalException異常的邏輯。
4、LoginController.java 修改doLogin方法,優化登錄邏輯。
寫在最后:方法的返回類型要根據業務方法含義來判斷,方法體內遇到的錯誤可以通過自定義異常封裝類和異常處理類來攔截再處理。
四、分布式Session
詳見github上的提交https://github.com/yanguobin/mymiaosha