<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
這個地方為什麼需要session? 因為我們需要把驗證碼儲存在session當中
/** * 傳送手機驗證碼 */ @PostMapping("code") public Result sendCode(@RequestParam("phone") String phone, HttpSession session) { // TODO 傳送簡訊驗證碼並儲存驗證碼 // return Result.fail("功能未完成"); return userService.sendCode(phone,session); }
2.2 業務層程式碼模擬傳送簡訊
@Override public Result sendCode(String phone, HttpSession session) { // 1.校驗手機號 if(RegexUtils.isPhoneInvalid(phone)){ // 說明:RegexUtils使我們封裝的一個類 isCodeInvalid是裡面的靜態方法,在這個靜態方法裡面又呼叫了另外一個靜態方法得以實現 // 2.如果不符合,返回錯誤資訊 return Result.fail("手機號格式錯誤"); } // 3.符合,生成驗證碼 6代表生成的驗證碼的長度 RandomUtil使用這個工具類生成 String code = RandomUtil.randomNumbers(6); // 4.儲存驗證碼到session key必須是一個字串,value是一個物件 session.setAttribute("code",code); // 5.傳送驗證碼 // 實現起來比較麻煩 我們使用紀錄檔假裝傳送 log.debug("傳送簡訊驗證碼成功,驗證碼:"+code); return Result.ok(); } }
/** * 登入功能 * @param loginForm 登入引數,包含手機號、驗證碼;或者手機號、密碼 */ @PostMapping("/login") public Result login(@RequestBody LoginFormDTO loginForm, HttpSession session){ // TODO 實現登入功能 return userService.login(loginForm,session); }
流程圖:
程式碼:
/** * 實現使用者登入 * @param loginForm 登入的引數 * @param session * @return */ @Override public Result login(LoginFormDTO loginForm, HttpSession session) { // 1.校驗手機號 if(RegexUtils.isPhoneInvalid(loginForm.getPhone())){ // 說明:RegexUtils使我們封裝的一個類 isCodeInvalid是裡面的靜態方法,在這個靜態方法裡面又呼叫了另外一個靜態方法得以實現 // 1.2.如果不符合,返回錯誤資訊 return Result.fail("手機號格式錯誤"); } // 2.校驗驗證碼 // 2.1 得到code 這個值是真實的code Object cacheCode = session.getAttribute("code"); // 2.2 獲取使用者輸入的code String code = loginForm.getCode(); if(cacheCode ==null || !cacheCode.toString().equals(code)){ // 3.不一致,報錯 return Result.fail("驗證碼錯誤"); } // 4.一致,根據手機號查詢使用者 .one()代表查詢一個 list()代表著查詢多個 User user =query().eq("phone",loginForm.getPhone()).one(); // 5.判斷使用者是否存在 if(user ==null){ // 6.不存在,建立新使用者並儲存 user = createUserWithPhone(loginForm.getPhone()); } // 7.儲存使用者資訊到session中 session.setAttribute("user",user); return Result.ok(); } private User createUserWithPhone(String phone) { // 1.建立使用者 User user = new User(); user.setPhone(phone); // USER_NICK_NAME_PREFIX其實就是 "user_",這樣寫更有逼格 user.setNickName(USER_NICK_NAME_PREFIX+RandomUtil.randomString(10)); // 儲存使用者 save(user); return user; }
// HandlerInterceptor 這是一個攔截器 public class LoginInterceptor implements HandlerInterceptor { // 前置攔截 在進入controller之前我們進行登入校驗 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 1.獲取session HttpSession session =request.getSession(); // 2.獲取session中的使用者 Object user = session.getAttribute("user"); // 3.判斷使用者是否存在 if(user == null){ // 4.不存在,攔截 response.setStatus(401); //返回401狀態碼 return false; } // 5.存在,儲存使用者資訊到ThreadLocal 儲存在當前執行緒裡面的 UserHolder.saveUser((User)user); // 6.放行 return true; } // 在controller執行之後攔截 這個我們在這裡不需要 // @Override // public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); // } // 渲染之後,返回給使用者之前 使用者業務執行完畢我們要銷燬維護資訊,避免洩露 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 移除使用者 UserHolder.removeUser(); } }
public class UserHolder { private static final ThreadLocal<User> tl = new ThreadLocal<>(); public static void saveUser(User user){ tl.set(user); } public static User getUser(){ return tl.get(); } public static void removeUser(){ tl.remove(); } }
@Configuration public class MvcConfig implements WebMvcConfigurer { // 攔截器的註冊器 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .excludePathPatterns( "/user/code", "/user/login", "/shop/**", "/blog/hot", "/shop-type/**", "upload/**", "voucher/**" ); } }
@GetMapping("/me") public Result me(){ // TODO 獲取當前登入的使用者並返回 // 直接取就可以了 User user= UserHolder.getUser(); return Result.ok(user); }
如下圖所示,伺服器返回的資訊有點多,我們為了保護使用者的資訊,我們需要隱藏部分的內容
所以一開始我們存入session的資訊就不應該是完整的資訊,這樣才能降低伺服器的壓力
UserServiceImpl中的login方法
// 7.儲存使用者資訊到session中 // BeanUtil.copyProperties(user, UserDTO.class)) 會自動的將user中的屬性拷貝到UserDTO當中而且也建立出一個UserDTO物件 session.setAttribute("user", BeanUtil.copyProperties(user, UserDTO.class));
取的時候我們也應該做出變化
LoginInterceptor類
// 5.存在,儲存使用者資訊到ThreadLocal 儲存在當前執行緒裡面的 UserHolder.saveUser((UserDTO)user);
此時我們再登入查詢資訊,就還剩下三個欄位了
多臺Tomcat並不共用session儲存空間,當請求切換到不同的Tomcat服務導致資料丟失的問題
所以這個方案就被pass了
session的替代方案應該滿足:
資料共用記憶體儲存key、value結構
所以我們選擇Redis
任何一臺Tomcat都能存取到Redis,這樣就能實現資料共用
到此這篇關於如何基於Session實現簡訊登入功能的文章就介紹到這了,更多相關Session簡訊登入內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45