電商項目面試總結


項目介紹:

整個項目采用分布式的架構設計,包括登錄系統、搜索系統(沒做)、購物車系統、訂單系統、支付系統等。整個項目采用nginx+tomcat來部署,nginx主要用來做反向代理和負載均衡。主要用redis來做登錄信息緩存,mysql做數據庫。自己參與了登錄系統的開發,包括注冊、單點登錄等功能模塊。

 

問題1:為什么要選用redis?

由於每個系統都單獨部署運行一個單獨的tomcat,所以,不能將用戶的登錄信息保存到session中(多個tomcat的session不共享),所以選用redis來緩存登錄信息,當用戶登錄時,將用戶登錄信息保存到redis中,並生成一個token保存到cookie中(不太確定是否是這么實現的?)

 

問題2:單點登錄系統的基本流程?

  當用戶點擊登錄按鈕的時候,用戶輸入用戶名和密碼,檢驗用戶名是否在數據庫中存在,然后用戶名密碼是否正確。這里的密碼是用了spring的MD5加密技術。當全部成功后,將sessionId(也可以生成一個UUID)寫入cookie中供前端調用,寫入瀏覽器的cookie中,然后存入到redis中(key是sessionId,value是用戶信息),並設置有效期。

  這里的cookie是設置了共同的name,所以不論是什么系統進行登錄,前端頁面都會存有這個name的cookie,也就實現了所有子系統都可以訪問到cookie。

  當用戶登錄其他子系統時,先從cookie中獲取token信息(也就是sessionId),根據token信息獲取用戶信息。用戶每次與網站的交互,比如查看產品,則刷新一次redis的時間,重新設置有效期,這個效果是通過攔截器來實現的。

  攔截器的攔截,在springMVC.xml中設置攔截的名稱。

登錄流程代碼:先寫cookie再寫redis.

 1     @RequestMapping(value = "login.do", method = RequestMethod.POST)
 2     @ResponseBody
 3     public ServerResponse<User> login(String username, String password, HttpSession session, HttpServletResponse httpServletResponse) {
 4         ServerResponse<User> response = iUserService.login(username, password);
 5         if(response.isSuccess()) {
 6             CookieUtil.writeLoginToken(httpServletResponse, session.getId());
 7             //sessionId是key,用戶的登錄信息是value,存在redis中
 8             //sessionId是tomcat中自動生成的,針對當前項目,每啟動一次,sessionId就變一次
 9             //設置session超時時間
10             RedisShardedPoolUtil.setEx(session.getId(), JsonUtil.obj2String(response.getData()), Const.RedisCacheExtime.REDIS_SESSION_EXTIME);
11 
12         }
13         return response;
14     }
View Code

 攔截器重置有效期:

 1 public class SessionExpireFilter implements Filter {
 2 
 3     @Override
 4     public void init(FilterConfig filterConfig) throws ServletException {
 5 
 6     }
 7 
 8     @Override
 9     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
10         HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;
11         String loginToken = CookieUtil.readLoginToken(httpServletRequest);
12         if(StringUtils.isNotEmpty(loginToken)) {
13             //判斷loginToken是否為空或者""
14             //如果不為空的話,符合條件,繼續拿user信息
15             String userJsonStr = RedisShardedPoolUtil.get(loginToken);
16             User user = JsonUtil.string2Obj(userJsonStr, User.class);
17             if(user != null) {
18                 //如果user不為空,則重置session的時間,即調用expire命令
19                 RedisShardedPoolUtil.expire(loginToken, Const.RedisCacheExtime.REDIS_SESSION_EXTIME);
20             }
21         }
22         filterChain.doFilter(servletRequest, servletResponse);
23     }
24 
25     @Override
26     public void destroy() {
27 
28     }
29 }
View Code

web.xml部署攔截器:

1     <filter>
2         <filter-name>sessionExpireFilter</filter-name>
3         <filter-class>com.mall.controller.common.SessionExpireFilter</filter-class>
4     </filter>
5     <filter-mapping>
6         <filter-name>sessionExpireFilter</filter-name>
7         <url-pattern>*.do</url-pattern>
8     </filter-mapping>
View Code

 

問題3:單點登錄之跨域問題?

  將cookie存在一個公共的站點的頁面上就可以了,這里我們管那個站點叫主站S。

  環境1:a.xxx.com需要跟b.xxx.com實現跨域,這種比較簡單,只需要設置cookie的域名關聯域就可以了 cookie.Domain = "xxx.com",這樣兩個域名間的cookie就可以互相訪問,實現跨域。【項目中使用的這種環境】

  環境2:a.aaa.com需要跟b.bbb.com實現跨域,這種不同域名的情況下,想要實現就必須換種方式.

  在這里我將引入第三者,s.sss.com這個站點,就是某個瀏覽器同時打開了這3個站點,我們訪問A站點,先判斷自身是否登錄,如果session為空,就重定向到S站點,判斷S站點上面是否有cookie,如果S站點上面也沒有cookie,則由S站點重定向到A站點的登錄頁.

  這樣我們就實現了第一步,S站做的的就是隱藏在幕后,子站先判斷自己是否存在session,如果不存在,就重定向到主站S上面去驗證.

  第二步,驗證登錄信息合法性.這里我引入token(令牌),網上有很多資料,描述token的傳遞,工作方式是這樣,A登錄成功,保存自身的session,重定向到S,S在自己站點保存一個session跟cookie,session保存token對象{tokenID,userName,startTime,endTime},cookie保存tokenID,tokenID是一個Guid,把token對象緩存在集合里面,另起一個線程,根據endTime(過期時間)來定期清理集合列表,重定向到A的時候再將tokenID傳遞過去,拿到tokenID后,進入驗證環節,S站有提供一個接口,根據tokenID獲取token對象,如果獲取到對象,且沒有失效,則tokenID合法,跳入index頁面.情況2,A登錄,直接打開B,這時候B自身沒有session,會主動請求主站,主站會返回cookieID(S站存在客戶端的cookie),這個時候再走驗證環節,如果通過,則B根據token對象創建自身的session,再跳入index。

 

問題4:忘記密碼找回密碼的流程?

  在注冊的時候會設置找回密碼的問題和答案,在非登錄狀態忘記密碼后,需要通過回答問題和答案找回密碼。根據用戶名找到用戶設置的問題,然后回答完問題后,生成一個UUID,緩存在redis中設置有效期,並返回這個UUID。然后前端將這個UUID和新密碼傳入重置密碼的函數,將傳入的UUID和之前緩存在redis中的UUID進行比較,如果相同,則對新密碼進行md5加密后更新到數據庫中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM