iT邦幫忙

0

應用系統建置前準備工具 - CookieUtils Cookie 工具

  • 分享至 

  • xImage
  •  

CookieUtils Cookie 工具類別

概述

CookieUtils 是一個用於管理 HTTP Cookie 的工具類別,提供設置、讀取和刪除 Cookie 的功能。此類別設計為靜態工具類別,所有方法皆可直接呼叫使用。

專案相關程式

  • GlobalConstants

第三方元件(Dependency)

  • jakarta.servlet-api

主要功能

1. Cookie 設置

基本設置

// 設置 Cookie(預設 1 天有效期)
CookieUtils.setCookie(response, "username", "john_doe");

// 設置 Cookie 並指定路徑
CookieUtils.setCookie(response, "theme", "dark", "/admin");

自訂有效期

// 設置 Cookie 並指定有效期(秒)
CookieUtils.setCookie(response, "session", "abc123", 3600);  // 1小時

// 設置 Cookie 並指定路徑和有效期
CookieUtils.setCookie(response, "preferences", "lang=zh", "/app", 7200);  // 2小時

2. Cookie 讀取

基本讀取

// 讀取 Cookie 值
String username = CookieUtils.getCookie(request, "username");

讀取並刪除

// 讀取 Cookie 值後立即刪除
String token = CookieUtils.getCookie(request, response, "auth_token");

條件讀取

// 讀取 Cookie 值並選擇是否刪除
String temp = CookieUtils.getCookie(request, response, "temp_data", true);   // 讀取後刪除
String perm = CookieUtils.getCookie(request, response, "perm_data", false);  // 僅讀取

重要注意事項

  1. Cookie 編碼

    • Cookie 值會自動使用 URL 編碼
    • 使用專案預設的字元集進行編碼/解碼
    • 編碼失敗時會記錄異常訊息
  2. 有效期設置

    • 預設有效期為 1 天(86400 秒)
    • 設置為 0 秒表示立即刪除 Cookie
    • 時間單位統一使用秒
  3. 路徑處理

    • 預設路徑為根路徑 "/"
    • 自訂路徑時需確保以 "/" 開頭
    • 路徑影響 Cookie 的可見範圍
  4. 錯誤處理

    • 讀取不存在的 Cookie 返回 null
    • 編碼/解碼錯誤會印出堆疊追蹤
    • Cookie 陣列為 null 時安全處理

使用場景

  1. 使用者資訊

    • 儲存登入狀態
    • 記住使用者偏好
    • 追蹤使用者設定
  2. 會話管理

    • 暫存會話令牌
    • 管理登入狀態
    • 實現記住我功能
  3. 臨時資料

    • 暫存表單資料
    • 跨請求訊息傳遞
    • 使用者操作追蹤

單元測試範例

以下測試範例示範 CookieUtils 的常見行為:

1. 設置與讀取 Cookie

@Test
void testSetAndGetCookie() {
   MockHttpServletResponse response = new MockHttpServletResponse();
   MockHttpServletRequest request = new MockHttpServletRequest();

   CookieUtils.setCookie(response, "username", "alice", 3600);
   // 模擬把 response 的 cookie 放到 request
   request.setCookies(response.getCookies());

   String value = CookieUtils.getCookie(request, "username");
   assertEquals("alice", value);
}

2. 讀取並刪除 Cookie

@Test
void testGetAndRemoveCookie() {
   MockHttpServletResponse response = new MockHttpServletResponse();
   MockHttpServletRequest request = new MockHttpServletRequest();

   CookieUtils.setCookie(response, "token", "abc123", 0);
   request.setCookies(response.getCookies());

   String token = CookieUtils.getCookie(request, new MockHttpServletResponse(), "token", true);
   // 刪除後再次讀取應為 null
   assertNull(CookieUtils.getCookie(request, "token"));
}

3. 編碼與空值處理

@Test
void testEncodingAndNull() {
   MockHttpServletResponse response = new MockHttpServletResponse();
   MockHttpServletRequest request = new MockHttpServletRequest();

   CookieUtils.setCookie(response, "data", "a b+c%", 3600);
   request.setCookies(response.getCookies());

   String decoded = CookieUtils.getCookie(request, "data");
   assertEquals("a b+c%", decoded);

   // 讀取不存在的 cookie
   assertNull(CookieUtils.getCookie(request, "not_exist"));
}

測試說明

  • 測試設置後能正確讀取與刪除
  • 測試 URL 編碼/解碼行為
  • 測試 null 與不存在 cookie 的安全處理

程式碼 CookieUtils.java

package tw.lewishome.webapp.base.utility.common;
 
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import tw.lewishome.webapp.GlobalConstants;

/**
 * Cookie 工具類,提供設置、取得及刪除 Cookie 的靜態方法。
 *
 * 主要功能:
 *
 * <ul>
 * <li>設置 Cookie,支援指定有效時間與路徑。</li>
 * <li>取得 Cookie 值,並可選擇是否同時刪除。</li>
 * </ul>
 *
 *
 * 所有 Cookie 值皆以指定字元集進行編碼與解碼。
 *
 *
 * @author Lewis
 * @since 1.0
 */
public class CookieUtils {
   /** Private constructor to prevent instantiation */
    private CookieUtils() {
        throw new IllegalStateException("This is a utility class and cannot be instantiated");
    }

    /**
     * 增加 Cookie(有效時間1天)
     *
     * @param response URL response物件
     * @param name     Cookie 名稱
     * @param value    Cookie內容
     */
    public static void setCookie(HttpServletResponse response, String name, String value) {
        setCookie(response, name, value, 60 * 60 * 24);
    }

    /**
     * 增加 指定 URL網址的 Cookie(有效時間1天)
     *
     * @param response URL response物件
     * @param name     Cookie 名稱
     * @param value    Cookie內容
     * @param path     URL網址
     */
    public static void setCookie(HttpServletResponse response, String name, String value, String path) {
        setCookie(response, name, value, path, 60 * 60 * 24);
    }

    /**
     * 增加 Cookie 指定 URL網址 (有效時間1天)
     *
     * @param response URL response物件
     * @param name     Cookie 名稱
     * @param value    Cookie內容
     * @param maxAge   有效時間(以秒為單位)
     */
    public static void setCookie(HttpServletResponse response, String name, String value, int maxAge) {
        setCookie(response, name, value, "/", maxAge);
    }

    /**
     * 增加 Cookie 指定 URL網址 以及 有效時間
     *
     * @param response URL response物件
     * @param name     Cookie 名稱
     * @param value    Cookie內容
     * @param maxAge   有效時間(以秒為單位)
     * @param path     URL網址
     */
    public static void setCookie(HttpServletResponse response, String name, String value, String path, int maxAge) {
        Cookie cookie = new Cookie(name, null);
        cookie.setPath(path);
        cookie.setMaxAge(maxAge);
        try {
            cookie.setValue(URLEncoder.encode(value, GlobalConstants.DEFAULT_CHAR_SET));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.addCookie(cookie);
    }

    /**
     * 取得指定Cookie的值
     *
     * @param request URL request 物件
     * @param name    Cookie 名稱
     * @return String Cookie內容
     */
    public static String getCookie(HttpServletRequest request, String name) {
        return getCookie(request, null, name, false);
    }

    /**
     * 取得指定Cookie的值並刪除
     *
     * @param request URL request 物件
     * @param name    Cookie 名稱
     * @return String Cookie內容
     * @param response a {@link jakarta.servlet.http.HttpServletResponse} object
     */
    public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name) {
        return getCookie(request, response, name, true);
    }

    /**
     * 取得指定Cookie的值 (選擇刪除與否)
     *
     * @param request  URL request 物件
     * @param response URL response 物件
     * @param name     Cookie 名稱
     * @param isRemove 是否移除
     * @return String Cookie內容
     */
    public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name,
            boolean isRemove) {
        String value = null;
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(name)) {
                    try {
                        value = URLDecoder.decode(cookie.getValue(), GlobalConstants.DEFAULT_CHAR_SET);
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    if (isRemove) {
                        cookie.setMaxAge(0);
                        response.addCookie(cookie);
                    }
                }
            }
        }
        return value;
    }
}

單元測試程式碼 CookieUtilsTest.java

package tw.lewishome.webapp.base.utility.common;


import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;


import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import tw.lewishome.webapp.GlobalConstants;




public class CookieUtilsTest {

    private HttpServletResponse response;
    private HttpServletRequest request;
    private ArgumentCaptor<Cookie> cookieCaptor;

   @BeforeEach
    public void setUp() {
        response = mock(HttpServletResponse.class);
        request = mock(HttpServletRequest.class);
        cookieCaptor = ArgumentCaptor.forClass(Cookie.class);
    }

    @Test
    void testPrivateConstructor() {
        assertThrows(IllegalAccessException.class, () -> {
            Aes256Utils.class.getDeclaredConstructor().newInstance();
        });
    }

    @Test
    public void testSetCookieDefaultPath() throws UnsupportedEncodingException {
        CookieUtils.setCookie(response, "name", "value");
        
        verify(response).addCookie(cookieCaptor.capture());
        Cookie cookie = cookieCaptor.getValue();
        
        assertEquals("name", cookie.getName());
        assertEquals(URLEncoder.encode("value", GlobalConstants.DEFAULT_CHAR_SET), cookie.getValue());
        assertEquals("/", cookie.getPath());
        assertEquals(24 * 60 * 60, cookie.getMaxAge());
    }

    @Test
    public void testSetCookieWithPath() throws UnsupportedEncodingException {
        CookieUtils.setCookie(response, "name", "value", "/custom");
        
        verify(response).addCookie(cookieCaptor.capture());
        Cookie cookie = cookieCaptor.getValue();
        
        assertEquals("name", cookie.getName());
        assertEquals(URLEncoder.encode("value", GlobalConstants.DEFAULT_CHAR_SET), cookie.getValue());
        assertEquals("/custom", cookie.getPath());
        assertEquals(24 * 60 * 60, cookie.getMaxAge());
    }

    @Test
    public void testGetCookieWhenCookieExists() {
        Cookie[] cookies = new Cookie[]{new Cookie("test", "value")};
        when(request.getCookies()).thenReturn(cookies);
        
        String result = CookieUtils.getCookie(request, "test");
        assertEquals("value", result);
    }

    @Test
    public void testGetCookieWhenCookieDoesNotExist() {
        Cookie[] cookies = new Cookie[]{new Cookie("other", "value")};
        when(request.getCookies()).thenReturn(cookies);
        
        String result = CookieUtils.getCookie(request, "test");
        assertNull(result);
    }

    @Test
    public void testGetCookieAndRemove() {
        Cookie testCookie = new Cookie("test", "value");
        Cookie[] cookies = new Cookie[]{testCookie};
        when(request.getCookies()).thenReturn(cookies);
        
        String result = CookieUtils.getCookie(request, response, "test");
        
        assertEquals("value", result);
        verify(response).addCookie(cookieCaptor.capture());
        assertEquals(0, cookieCaptor.getValue().getMaxAge());
    }
    
    @Test
    public void testGetCookieWithNullCookies() {
        when(request.getCookies()).thenReturn(null);
        
        String result = CookieUtils.getCookie(request, "test");
        assertNull(result);
    }
}

圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言