/**
  * 将cookie保存到response中
  *
  * @param ac
  * @param value
  * @param removed
  */
 private void addCookieToResponse(AttributeConfigDO ac, String value, boolean removed) {
   String name = ac.getClientKey();
   String domain = ac.getDomain();
   // 删除cookie时将maxAge设为0
   int maxAge = (removed || value == null) ? 0 : ac.getLifeCycle();
   String path = ac.getCookiePath();
   boolean httpOnly = ac.isHttpOnly();
   addCookieToResponse(name, value, domain, maxAge, path, httpOnly);
 }
 /**
  * 从cookie里取
  *
  * @param ac
  * @return
  */
 private AttributeDO getAttributeFromCookies(AttributeConfigDO ac) {
   String clientKey = ac.getClientKey();
   String cookieValue = cookies.get(clientKey);
   String v = decodeValue(cookieValue, ac);
   AttributeDO attribute = new AttributeDO(ac, v);
   return attribute;
 }
 @Override
 public void setAttribute(AttributeConfigDO ac, Object value) {
   String key = ac.getKey();
   // XXX 注意,这里调用了value上的toString(),而不是保存value对象本身
   String v = value == null ? null : value.toString();
   AttributeDO attribute = new AttributeDO(ac, v);
   attributes.put(key, attribute);
   dirty.add(key); // 标记修改
 }
  @Override
  public Object getAttribute(AttributeConfigDO ac) {
    String key = ac.getKey();

    // 先从已解析中获取
    AttributeDO attribute = attributes.get(key);
    if (attribute == null) {
      attribute = getAttributeFromCookies(ac);

      // 保存到已解析map
      attributes.put(key, attribute);
    }

    return attribute.getValue();
  }
  /**
   * 编码
   *
   * @param value
   * @param ac
   * @return
   */
  private String encodeValue(String value, AttributeConfigDO ac) {
    if (StringUtils.isEmpty(value)) {
      return value;
    }

    if (ac.isEncrypt()) {
      value = BlowfishUtils.encryptBlowfish(value, CRYPT_KEY);
    }

    try {
      value = URLEncoder.encode(value, "UTF-8");
    } catch (Exception e) {
      log.error("编码失败, value=" + value, e);
      // 编码失败时,返回错误标记,且不保存到cookies中
      return ERROR;
    }
    return value;
  }
  /**
   * 解码
   *
   * @param value
   * @param ac
   * @return
   */
  private String decodeValue(String value, AttributeConfigDO ac) {
    if (value == null) {
      return value;
    }

    try {
      value = URLDecoder.decode(value, "UTF-8");
    } catch (Exception e) {
      // logger.error("解码失败", e);
      // 解码失败时直接返回,不继续解析
      return value;
    }

    if (ac.isEncrypt()) {
      value = BlowfishUtils.decryptBlowfish(value, CRYPT_KEY);
    }

    return value;
  }