在上一階段我們完成購物車的基本操作,但仍缺少一個關鍵環節:當使用者點擊「結帳」時,系統必須先判斷使用者是否已登入。若未登入,需攔截請求並導向登入頁;登入成功後,再自動跳回原本想前往的頁面(如訂單確認頁)。這正是 Servlet Filter(過濾器)的經典應用場景。
整個流程可拆解為三步:
web.xml 設定需攔截的 URL 模式(如 /user/confirm.jsp),當使用者請求符合模式時,容器會先執行自訂 Filter。user 屬性。若無,表示未登入,則將「原始請求路徑 + 參數」組合並存入 Session(鍵名 goURL),再重導向至登入頁(ulogin.jsp)。chain.doFilter() 放行;登入成功後,Action 會讀取 Session 中的 goURL 決定跳轉目標。public class UserFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化邏輯(若有)
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
// 1. 檢查 Session 是否有登入用戶
if (req.getSession().getAttribute("user") == null) {
// 2. 保存原始請求 URL 含參數
String goURL = req.getServletPath();
String queryString = req.getQueryString();
if (queryString != null) {
goURL += "?" + queryString;
}
req.getSession().setAttribute("goURL", goURL);
req.getSession().setAttribute("error", "請先登入!");
// 3. 重導向至登入頁
res.sendRedirect(req.getContextPath() + "/ulogin.jsp");
} else {
// 已登入,放行
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
// 銷毀邏輯(若有)
}
}
<filter>
<filter-name>UserFilter</filter-name>
<filter-class>com.shop.filter.UserFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UserFilter</filter-name>
<url-pattern>/user/confirm.jsp</url-pattern>
</filter-mapping>
@Controller("userAction")
@Scope("prototype")
public class UserAction extends BaseAction<User> {
public String login() {
// 驗證帳密
model = userService.login(model);
if (model == null) {
session.put("error", "登入失敗");
return "login";
}
// 登入成功,存入 Session
session.put("user", model);
// 依 goURL 決定跳轉
if (session.get("goURL") == null) {
return "index"; // 無導向目標,回首頁
} else {
return "goURL"; // 有導向目標,交由 Struts 結果型別處理
}
}
}
<action name="user_*" class="userAction" method="{1}">
<result name="login">/ulogin.jsp</result>
<result name="index">/index.jsp</result>
<result name="goURL" type="redirect">${session.goURL}</result>
</action>
關鍵在於 type="redirect" 搭配 ${session.goURL},利用 OGNL 表達式從 Session 取出原始 URL 並重導向。
@Service("userService")
public class UserServiceImpl extends BaseServiceImpl<User> implements UserService {
@Override
public User login(User user) {
String hql = "FROM User u WHERE u.login = :login AND u.pass = :pass";
return (User) getSession()
.createQuery(hql)
.setParameter("login", user.getLogin())
.setParameter("pass", user.getPass())
.uniqueResult();
}
}
目前攔截點在「訂單確認頁」,更理想的是在「加入購物車」前就檢查登入狀態。但因加入購物車是透過 Action 處理,若要攔截 Action 請求,應改用 Struts2 Interceptor(攔截器) 而非 Filter。後續篇幅將補充 Interceptor 實作。
本文示範如何以 Servlet Filter 實作「登入攔截 → 保存目標 URL → 登入後自動導回」的完整流程,搭配 Struts2 結果型別靈活導向,達到無縫購物體驗。程式碼結構清晰,易於擴充與維護。