public ValidatorConfigBean create(String fieldName, ValidatorConfigBean val) {
    if (this.ann == null) return null;
    if (val == null || !Validators.ENUM.equals(val.getName())) {
      val = new ValidatorConfigBean();
      val.setName(Validators.ENUM);
    }

    FieldConfigBean fcb = new FieldConfigBean();
    fcb.setName(fieldName);
    fcb.setMessage(CommonUtil.parsePropValue(ann.mess()));
    ParamConfigBean pcb = new ParamConfigBean();
    pcb.setName(Validators.ENUM_WORD_PARAM);
    StringBuilder sb = new StringBuilder();
    for (String s : ann.words()) {
      if (sb.length() > 0) sb.append("#");

      sb.append(CommonUtil.parsePropValue(s));
    }

    pcb.setValue(sb.toString());
    fcb.getParam().add(pcb);

    val.getField().add(fcb);

    return val;
  }
  /**
   * 解析 Uri Mapping 的前部分
   *
   * @param cls
   * @param moduleName
   * @return
   */
  private static String parseUriMappingPrefix(Class<?> cls, String moduleName) {
    Path cls_path = cls.getAnnotation(Path.class);
    String clazzUriMapping = cls_path == null ? moduleName : cls_path.value();

    clazzUriMapping = CommonUtil.parsePropValue(clazzUriMapping);

    return clazzUriMapping;
  }
  private static List<String> parseProduces(Method m) {
    // 读取@Produces注解
    Produces producesAnn = m.getAnnotation(Produces.class);
    List<String> pcbs = null;
    if (producesAnn != null) {
      pcbs = new ArrayList<String>();
      String producesStr = CommonUtil.parsePropValue(producesAnn.value()[0]);
      pcbs.add(producesStr);
    }

    return pcbs;
  }
  private static String parseShowValErrType(Class<?> cls, Method m) {
    ShowValMess cls_vm = cls.getAnnotation(ShowValMess.class);
    String clsShowValErr = cls_vm == null ? "alert" : cls_vm.value();

    clsShowValErr = CommonUtil.parsePropValue(clsShowValErr);

    String methodShowValErr =
        clsShowValErr.trim().length() == 0 ? "alert" : clsShowValErr; // 验证器验证信息输出方式默认”alert“

    ShowValMess m_vm = m.getAnnotation(ShowValMess.class);
    methodShowValErr = m_vm == null ? methodShowValErr : m_vm.value();

    return methodShowValErr;
  }
  @Validate({"user.authcode", "user.account", "user.password"})
  public Object doLoginAtPut(Validation val, Map<String, Object> model) {
    if (val.hasErr()) {
      model.put("valError", val.getAllErr());
      return UserCons.LOGIN_ACTION_RESULT();
    }

    List<Long> treeMenuPerms = new ArrayList<Long>();
    List<Long> navMenuPerms = new ArrayList<Long>();
    try {
      String _authCode =
          (String) MVC.ctx().getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
      User loginUser =
          userService.login(_authCode, CommonUtil.getIpAddr(MVC.ctx().getRequest()), user);

      // 登陆成功之后,将用户的权限信息查询出来放到session内存中
      /* 权限控制 */
      List<Role> roles = loginUser.getRoles();
      if (roles == null) roles = new ArrayList<Role>();

      for (Role role : roles) {
        Role _role = roleService.findTreeMenuByRoleId(role.getRoleId());
        /* 角色对应权限集合 */
        List<TreeMenu> tms = _role.getMenus();
        List<NavMenu> nms = _role.getNavMenus();

        if (tms != null) {
          for (TreeMenu tm : tms) treeMenuPerms.add(tm.getTreeMenuId());
        }
        if (nms != null) {
          for (NavMenu nm : nms) navMenuPerms.add(nm.getNavMenuId());
        }
      }

      loginUser.setTreeMenuPerms(treeMenuPerms);
      loginUser.setNavMenuPerms(navMenuPerms);

      MVC.ctx().getSession().setAttribute(UserCons.LOGIN_USER_ATTR_NAME(), loginUser);

    } catch (Exception e) {
      model.put(UserCons.LOGIN_ERR_ATTR_NAME(), e.getMessage());
      return UserCons.LOGIN_ACTION_RESULT();
    }

    return UserCons.LOGIN_SUCCESS_REDIRECT();
  }
  public static void handleActionRedirect(Context context, String path, String baseUrl)
      throws IOException {
    String method;
    String location;
    if (!path.contains("@")) {
      method = HttpMethod.GET;
      location = path;
    } else {
      int lastIndex = path.indexOf("@") + 1;
      method = path.substring(lastIndex);
      location = path.substring(0, lastIndex - 1);
    }
    StringBuilder sb = new StringBuilder("");
    String param = null;
    if (path.contains("?")) {
      int lastIndex2 = path.indexOf("?") + 1;
      param = path.substring(lastIndex2);
      String[] params = param.split("&");
      for (String para : params) {
        String[] p = para.split("=");
        sb.append(String.format("<input name='%s' value='%s' />", p[0], p[1]));
      }

      method = method.substring(0, method.indexOf("?"));
    }

    if (HttpMethod.GET.equalsIgnoreCase(method)) {
      String pa = param == null ? "" : "?" + CommonUtil.replaceChinese2Utf8(param);
      context.getResponse().sendRedirect(baseUrl + location + pa);
      return;
    }

    String _method = "";
    if (HttpMethod.PUT.equalsIgnoreCase(method) || HttpMethod.DELETE.equalsIgnoreCase(method)) {
      _method = new String(method);
      method = HttpMethod.POST;
    }

    String action = baseUrl + location;
    // 构造一个Form表单模拟客户端发送新的Action请求
    String format =
        "<form id='ACTION_REDIRECT_FORM' action='%s' method='%s' ><input name='_method' value='%s' />%s<input type='submit' /></form>";
    String form = String.format(format, action, method, _method, sb.toString());
    String js = "<script>document.getElementById('ACTION_REDIRECT_FORM').submit();</script>";
    context.getWriter().print(form + js);
  }
  // IOC,注入对象到pojo
  private void injectIocBean() throws Exception {
    fields = ru.getFields();
    if (fields == null) return;

    for (Field f : fields) {
      Class<?> type = f.getType();

      Ioc ioc = f.getAnnotation(Ioc.class);
      if (ioc == null) continue;
      String beanId = "";
      if (ioc.value().trim().length() == 0) beanId = type.getSimpleName();
      else beanId = CommonUtil.parsePropValue(ioc.value());

      Method setter = ru.getSetter(f.getName());
      if (setter == null) continue;

      setter.invoke(this.actionObject, IOC.getBean(beanId));
    }
  }
  /**
   * 请求
   *
   * @date 2013-1-7 上午11:08:54
   * @param toFetchURL
   * @return
   */
  public FetchResult request(FetchRequest req) throws Exception {
    FetchResult fetchResult = new FetchResult();
    HttpUriRequest request = null;
    HttpEntity entity = null;
    String toFetchURL = req.getUrl();
    boolean isPost = false;
    try {
      if (Http.Method.GET.equalsIgnoreCase(req.getHttpMethod())) request = new HttpGet(toFetchURL);
      else if (Http.Method.POST.equalsIgnoreCase(req.getHttpMethod())) {
        request = new HttpPost(toFetchURL);
        isPost = true;
      } else if (Http.Method.PUT.equalsIgnoreCase(req.getHttpMethod()))
        request = new HttpPut(toFetchURL);
      else if (Http.Method.HEAD.equalsIgnoreCase(req.getHttpMethod()))
        request = new HttpHead(toFetchURL);
      else if (Http.Method.OPTIONS.equalsIgnoreCase(req.getHttpMethod()))
        request = new HttpOptions(toFetchURL);
      else if (Http.Method.DELETE.equalsIgnoreCase(req.getHttpMethod()))
        request = new HttpDelete(toFetchURL);
      else throw new Exception("Unknown http method name");

      // 同步信号量,在真正对服务端进行访问之前进行访问间隔的控制
      // TODO 针对每个请求有一个delay的参数设置
      synchronized (mutex) {
        // 获取当前时间
        long now = (new Date()).getTime();
        // 对同一个Host抓取时间间隔进行控制,若在设置的时限内则进行休眠
        if (now - lastFetchTime < config.getPolitenessDelay())
          Thread.sleep(config.getPolitenessDelay() - (now - lastFetchTime));
        // 不断更新最后的抓取时间,注意,是针对HOST的,不是针对某个URL的
        lastFetchTime = (new Date()).getTime();
      }

      // 设置请求GZIP压缩,注意,前面必须设置GZIP解压缩处理
      request.addHeader("Accept-Encoding", "gzip");
      for (Iterator<Entry<String, String>> it = headers.entrySet().iterator(); it.hasNext(); ) {
        Entry<String, String> entry = it.next();
        request.addHeader(entry.getKey(), entry.getValue());
      }

      // 记录请求信息
      Header[] headers = request.getAllHeaders();
      for (Header h : headers) {
        Map<String, List<String>> hs = req.getHeaders();
        String key = h.getName();
        List<String> val = hs.get(key);
        if (val == null) val = new ArrayList<String>();
        val.add(h.getValue());

        hs.put(key, val);
      }
      req.getCookies().putAll(this.cookies);
      fetchResult.setReq(req);

      HttpEntity reqEntity = null;
      if (Http.Method.POST.equalsIgnoreCase(req.getHttpMethod())
          || Http.Method.PUT.equalsIgnoreCase(req.getHttpMethod())) {
        if (!req.getFiles().isEmpty()) {
          reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
          for (Iterator<Entry<String, List<File>>> it = req.getFiles().entrySet().iterator();
              it.hasNext(); ) {
            Entry<String, List<File>> e = it.next();
            String paramName = e.getKey();
            for (File file : e.getValue()) {
              // For File parameters
              ((MultipartEntity) reqEntity).addPart(paramName, new FileBody(file));
            }
          }

          for (Iterator<Entry<String, List<Object>>> it = req.getParams().entrySet().iterator();
              it.hasNext(); ) {
            Entry<String, List<Object>> e = it.next();
            String paramName = e.getKey();
            for (Object paramValue : e.getValue()) {
              // For usual String parameters
              ((MultipartEntity) reqEntity)
                  .addPart(
                      paramName,
                      new StringBody(
                          String.valueOf(paramValue), "text/plain", Charset.forName("UTF-8")));
            }
          }
        } else {
          List<NameValuePair> params = new ArrayList<NameValuePair>(req.getParams().size());
          for (Iterator<Entry<String, List<Object>>> it = req.getParams().entrySet().iterator();
              it.hasNext(); ) {
            Entry<String, List<Object>> e = it.next();
            String paramName = e.getKey();
            for (Object paramValue : e.getValue()) {
              params.add(new BasicNameValuePair(paramName, String.valueOf(paramValue)));
            }
          }
          reqEntity = new UrlEncodedFormEntity(params, HTTP.UTF_8);
        }

        if (isPost) ((HttpPost) request).setEntity(reqEntity);
        else ((HttpPut) request).setEntity(reqEntity);
      }

      // 执行请求,获取服务端返回内容
      HttpResponse response = httpClient.execute(request);
      headers = response.getAllHeaders();
      for (Header h : headers) {
        Map<String, List<String>> hs = fetchResult.getHeaders();
        String key = h.getName();
        List<String> val = hs.get(key);
        if (val == null) val = new ArrayList<String>();
        val.add(h.getValue());

        hs.put(key, val);
      }
      // 设置已访问URL
      fetchResult.setFetchedUrl(toFetchURL);
      String uri = request.getURI().toString();
      if (!uri.equals(toFetchURL))
        if (!URLCanonicalizer.getCanonicalURL(uri).equals(toFetchURL))
          fetchResult.setFetchedUrl(uri);

      entity = response.getEntity();
      // 服务端返回的状态码
      int statusCode = response.getStatusLine().getStatusCode();
      if (statusCode != HttpStatus.SC_OK) {
        if (statusCode != HttpStatus.SC_NOT_FOUND) {
          Header locationHeader = response.getFirstHeader("Location");
          // 如果是301、302跳转,获取跳转URL即可返回
          if (locationHeader != null
              && (statusCode == HttpStatus.SC_MOVED_PERMANENTLY
                  || statusCode == HttpStatus.SC_MOVED_TEMPORARILY))
            fetchResult.setMovedToUrl(
                URLCanonicalizer.getCanonicalURL(locationHeader.getValue(), toFetchURL));
        }
        // 只要不是OK的除了设置跳转URL外设置statusCode即可返回
        // 判断是否有忽略状态码的设置
        if (this.site.getSkipStatusCode() != null
            && this.site.getSkipStatusCode().trim().length() > 0) {
          String[] scs = this.site.getSkipStatusCode().split(",");
          for (String code : scs) {
            int c = CommonUtil.toInt(code);
            // 忽略此状态码,依然解析entity
            if (statusCode == c) {
              assemPage(fetchResult, entity);
              break;
            }
          }
        }
        fetchResult.setStatusCode(statusCode);
        return fetchResult;
      }

      // 处理服务端返回的实体内容
      if (entity != null) {
        fetchResult.setStatusCode(statusCode);
        assemPage(fetchResult, entity);
        return fetchResult;
      }
    } catch (Throwable e) {
      fetchResult.setFetchedUrl(e.toString());
      fetchResult.setStatusCode(Status.INTERNAL_SERVER_ERROR.ordinal());
      return fetchResult;
    } finally {
      try {
        if (entity == null && request != null) request.abort();
      } catch (Exception e) {
        throw e;
      }
    }

    fetchResult.setStatusCode(Status.UNSPECIFIED_ERROR.ordinal());
    return fetchResult;
  }
  /**
   * 抓取目标url的内容
   *
   * @date 2013-1-7 上午11:08:54
   * @param toFetchURL
   * @return
   */
  public FetchResult fetch(FetchRequest req) throws Exception {
    if (req.getHttpMethod() != null && !Http.Method.GET.equals(req.getHttpMethod())) {
      // 获取到URL后面的QueryParam
      String query = new URL(req.getUrl()).getQuery();
      for (String q : query.split("\\&")) {
        String[] qv = q.split("=");
        String name = qv[0];
        String val = qv[1];
        List<Object> vals = req.getParams().get(name);
        if (vals == null) {
          vals = new ArrayList<Object>();
          req.getParams().put(name, vals);
        }

        vals.add(val);
      }

      return request(req);
    }
    FetchResult fetchResult = new FetchResult();
    HttpGet get = null;
    HttpEntity entity = null;
    String toFetchURL = req.getUrl();
    try {
      get = new HttpGet(toFetchURL);
      // 设置请求GZIP压缩,注意,前面必须设置GZIP解压缩处理
      get.addHeader("Accept-Encoding", "gzip");
      for (Iterator<Entry<String, String>> it = headers.entrySet().iterator(); it.hasNext(); ) {
        Entry<String, String> entry = it.next();
        get.addHeader(entry.getKey(), entry.getValue());
      }

      // 同步信号量,在真正对服务端进行访问之前进行访问间隔的控制
      // TODO 针对每个请求有一个delay的参数设置
      synchronized (mutex) {
        // 获取当前时间
        long now = (new Date()).getTime();
        // 对同一个Host抓取时间间隔进行控制,若在设置的时限内则进行休眠
        if (now - lastFetchTime < config.getPolitenessDelay())
          Thread.sleep(config.getPolitenessDelay() - (now - lastFetchTime));
        // 不断更新最后的抓取时间,注意,是针对HOST的,不是针对某个URL的
        lastFetchTime = (new Date()).getTime();
      }

      // 记录get请求信息
      Header[] headers = get.getAllHeaders();
      for (Header h : headers) {
        Map<String, List<String>> hs = req.getHeaders();
        String key = h.getName();
        List<String> val = hs.get(key);
        if (val == null) val = new ArrayList<String>();
        val.add(h.getValue());

        hs.put(key, val);
      }

      req.getCookies().putAll(this.cookies);

      fetchResult.setReq(req);
      // 执行get访问,获取服务端返回内容
      HttpResponse response = httpClient.execute(get);
      headers = response.getAllHeaders();
      for (Header h : headers) {
        Map<String, List<String>> hs = fetchResult.getHeaders();
        String key = h.getName();
        List<String> val = hs.get(key);
        if (val == null) val = new ArrayList<String>();
        val.add(h.getValue());

        hs.put(key, val);
      }
      // 设置已访问URL
      fetchResult.setFetchedUrl(toFetchURL);
      String uri = get.getURI().toString();
      if (!uri.equals(toFetchURL))
        if (!URLCanonicalizer.getCanonicalURL(uri).equals(toFetchURL))
          fetchResult.setFetchedUrl(uri);

      entity = response.getEntity();
      // 服务端返回的状态码
      int statusCode = response.getStatusLine().getStatusCode();
      if (statusCode != HttpStatus.SC_OK) {
        if (statusCode != HttpStatus.SC_NOT_FOUND) {
          Header locationHeader = response.getFirstHeader("Location");
          // 如果是301、302跳转,获取跳转URL即可返回
          if (locationHeader != null
              && (statusCode == HttpStatus.SC_MOVED_PERMANENTLY
                  || statusCode == HttpStatus.SC_MOVED_TEMPORARILY))
            fetchResult.setMovedToUrl(
                URLCanonicalizer.getCanonicalURL(locationHeader.getValue(), toFetchURL));
        }
        // 只要不是OK的除了设置跳转URL外设置statusCode即可返回
        // 判断是否有忽略状态码的设置
        if (this.site.getSkipStatusCode() != null
            && this.site.getSkipStatusCode().trim().length() > 0) {
          String[] scs = this.site.getSkipStatusCode().split(",");
          for (String code : scs) {
            int c = CommonUtil.toInt(code);
            // 忽略此状态码,依然解析entity
            if (statusCode == c) {
              assemPage(fetchResult, entity);
              break;
            }
          }
        }
        fetchResult.setStatusCode(statusCode);
        return fetchResult;
      }

      // 处理服务端返回的实体内容
      if (entity != null) {
        fetchResult.setStatusCode(statusCode);
        assemPage(fetchResult, entity);
        return fetchResult;
      }
    } catch (Throwable e) {
      fetchResult.setFetchedUrl(e.toString());
      fetchResult.setStatusCode(Status.INTERNAL_SERVER_ERROR.ordinal());
      return fetchResult;
    } finally {
      try {
        if (entity == null && get != null) get.abort();
      } catch (Exception e) {
        throw e;
      }
    }

    fetchResult.setStatusCode(Status.UNSPECIFIED_ERROR.ordinal());
    return fetchResult;
  }
  /**
   * handle action class
   *
   * @param clsName
   * @throws Exception
   */
  public boolean handleClass(String clsName) {

    // log.debug("handleClass -> " + clsName);

    Class<?> cls = null;
    try {
      cls = Class.forName(clsName);

      if (cls == null) return false;

      String simpleName = cls.getSimpleName();
      Controller controlAnn = cls.getAnnotation(Controller.class);
      if (controlAnn == null
          && !simpleName.endsWith("Controller")
          && !simpleName.endsWith("Action")
          && !simpleName.endsWith("Control")) return false;

      String moduleName =
          CommonUtil.toLowCaseFirst(simpleName.replace("Controller", "").replace("Control", ""));
      if (simpleName.endsWith("Action")) {
        moduleName = "";
      }

      Object obj = null;
      try {
        if (cls.getAnnotation(Singleton.class) != null) {
          obj = SingleBeanCache.get(cls.getName());
          if (obj == null) {
            obj = cls.newInstance();
            SingleBeanCache.add(cls.getName(), obj);
          }
        } else obj = cls.newInstance();

      } catch (Error er) {
        // er.printStackTrace();
        log.debug("the action class new instance failued -> " + clsName + " | " + er.toString());
        return false;
      } catch (Exception e) {
        // e.printStackTrace();
        log.warn("the action class new instance failued -> " + clsName + " | " + e.toString());
        return false;
      }

      ReflectUtil ru = new ReflectUtil(obj);
      Method[] ms = ru.getMethods();
      if (ms == null) return false;

      // 扫描方法的注解信息
      for (Method m : ms) {
        if (m.getModifiers() != 1) continue;

        Path path = m.getAnnotation(Path.class);

        if (path == null) {
          String methodName = m.getName();
          Method getter = ru.getGetter(methodName.replace("get", ""));
          Method setter = ru.getSetter(methodName.replace("set", ""));
          // 默认下setter和getter不作为action方法
          if (getter != null || setter != null) continue;
        }

        handleActionConfigInfo(ru, cls, m, moduleName);
      }
    } catch (Error e) {
      return false;
    } catch (Exception e) {
      return false;
    }

    return true;
  }
  /**
   * 解析 URI Mapping 后部分
   *
   * @param moduleName
   * @param m
   * @return
   */
  private ActionConfigBean parseUriMappingSuffix(String moduleName, Method m) {
    ActionConfigBean acb = new ActionConfigBean();

    String methodName = m.getName();
    String fullName = m.toString();
    log.debug("parse action.method --> " + fullName);

    String uriMapping = null;
    Path m_path = m.getAnnotation(Path.class);
    if (methodName.startsWith(ActionMethod.PREFIX)) {
      uriMapping = methodName.substring(ActionMethod.PREFIX.length());
      // doUriBindParam1AndParam2JoinUriAtPostOrGet
      String at = null;
      int indexOfAt = methodName.indexOf(ActionMethod.AT);
      if (indexOfAt != -1) {
        at = methodName.substring(indexOfAt + ActionMethod.AT.length());
        if (methodName.startsWith(ActionMethod.PREFIX))
          uriMapping = uriMapping.substring(0, uriMapping.indexOf(ActionMethod.AT));
        String[] httpMethods = at.split(ActionMethod.OR);
        StringBuilder sb = new StringBuilder();
        for (String httpMethod : httpMethods) {
          if (sb.length() > 0) sb.append("|");

          sb.append(httpMethod.toUpperCase());
        }
        if (sb.length() > 0) {
          acb.setHttpMethod(sb.toString());
        }
      }
      String join = "";
      String bind;
      int indexOfBind = methodName.indexOf(ActionMethod.BIND);
      if (indexOfBind != -1) {
        if (indexOfAt != -1 && indexOfAt > indexOfBind) {
          bind = methodName.substring(indexOfBind + ActionMethod.BIND.length(), indexOfAt);
        } else {
          bind = methodName.substring(indexOfBind + ActionMethod.BIND.length());
        }

        uriMapping = uriMapping.substring(0, uriMapping.indexOf(ActionMethod.BIND));

        int indexOfJoin = bind.indexOf(ActionMethod.JOIN);
        if (indexOfJoin != -1) {
          String[] joins = bind.split(ActionMethod.JOIN);
          if (joins.length > 1) {
            bind = joins[0];
            join = joins[1];
          }
        }

        String[] pathParams = bind.split(ActionMethod.AND);
        StringBuilder pathParamSB = new StringBuilder();
        for (int i = 0; i < pathParams.length; i++) {
          pathParams[i] = CommonUtil.toLowCaseFirst(pathParams[i]);
          pathParamSB.append("/{").append(pathParams[i]).append("}");
        }

        if (pathParamSB.length() > 0) uriMapping = uriMapping + pathParamSB.toString();

        acb.setPathParams(pathParams);
      }

      uriMapping = CommonUtil.toLowCaseFirst(uriMapping);
      uriMapping = CommonUtil.hump2ohter(uriMapping, "-");

      if (join.length() > 0) {
        join = CommonUtil.toLowCaseFirst(join);
        join = CommonUtil.hump2ohter(join, "-");
        uriMapping = uriMapping + "/" + join;
      }

    } else if (m_path == null) {
      /* 8 个默认方法 */
      ActionConfigBean defaultAcb = parseDefaultActionConfig(methodName, moduleName);
      if (defaultAcb != null) {
        acb.setHttpMethod(defaultAcb.getHttpMethod());
        acb.getResult().addAll(defaultAcb.getResult());

        uriMapping = defaultAcb.getUriMapping();
      } else {

        String info =
            fullName
                + " does not starts with '"
                + ActionMethod.PREFIX
                + "' so that can not be a valid action uri mapping";
        log.debug(info);
        return null;
      }
    }

    if (m_path != null) {
      uriMapping = CommonUtil.parsePropValue(m_path.value());
    }

    acb.setUriMapping(uriMapping);
    return acb;
  }
  public void validateUpload() throws Exception {
    String tmpDir = null;
    long memoryMax = 0;
    long allSizeMax = 0;
    long oneSizeMax = 0;
    String[] suffixArray = null;
    Upload _upload = method.getAnnotation(Upload.class);
    if (_upload != null) {
      if (_upload.tmpDir().trim().length() > 0) tmpDir = _upload.tmpDir();

      if (_upload.maxMemorySize().trim().length() > 0)
        memoryMax = CommonUtil.strToInt(CommonUtil.parseFileSize(_upload.maxMemorySize()) + "");

      if (_upload.maxRequestSize().trim().length() > 0)
        allSizeMax = CommonUtil.parseFileSize(_upload.maxRequestSize());

      if (_upload.maxFileSize().trim().length() > 0)
        oneSizeMax = CommonUtil.parseFileSize(_upload.maxFileSize());

      if (_upload.suffix().length > 0) suffixArray = _upload.suffix();
    }

    long countAllSize = 0;
    for (Iterator<Entry<String, List<UploadFile>>> it =
            this.context.getUploadMap().entrySet().iterator();
        it.hasNext(); ) {
      Entry<String, List<UploadFile>> e = it.next();
      String fieldName = e.getKey();
      List<UploadFile> files = e.getValue();
      for (UploadFile file : files) {
        String fileName = file.getFileName();
        String fileContentType = file.getContentType();
        if (suffixArray != null && suffixArray.length > 0) {
          boolean isOk = false;
          for (String suffix : suffixArray) {
            if (fileName.endsWith("." + suffix)) {
              isOk = true;
              break;
            }
          }

          if (!isOk) {
            String err =
                "your upload file "
                    + fileName
                    + " type invalid ! only allow "
                    + Arrays.asList(suffixArray);
            Map<String, String> errMap = new HashMap<String, String>();
            errMap.put(fieldName, err);
            context.getValidation().getErrors().put("upload", errMap);
            return;
          }
        }
        long fileSize = file.getSize();
        if (fileSize > oneSizeMax) {
          Map<String, String> errMap = new HashMap<String, String>();
          String err =
              "your upload file " + fileName + " size overflow, only allow less than " + oneSizeMax;
          errMap.put(fieldName, err);
          context.getValidation().getErrors().put("upload", errMap);
          return;
        }

        countAllSize += fileSize;
        if (countAllSize > allSizeMax) {
          Map<String, String> errMap = new HashMap<String, String>();
          String err = "your upload files all size overflow, only allow less than " + allSizeMax;
          errMap.put(fieldName, err);
          context.getValidation().getErrors().put("upload", errMap);
          return;
        }
      }
    }
  }
  private void handleResult() throws Exception {

    this.exeActionLog();

    if (retn == null) return;
    String baseUrl =
        (String) this.context.getServletContext().getAttribute(MVCConfigConstant.BASE_URL_KEY);
    if (File.class.isAssignableFrom(retn.getClass())) {
      File file = (File) retn;
      this.handleDownload(file);
      return;
    } else if (File[].class.isAssignableFrom(retn.getClass())) {
      File[] files = (File[]) retn;

      String fileName = CommonUtil.getNowTime("yyyyMMddHHmmss") + "_" + "download.zip";

      HttpServletResponse resp = this.context.getResponse();
      resp.reset();
      resp.setContentType("application/zip");
      resp.addHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");

      ServletOutputStream outputStream = resp.getOutputStream();
      ZipOutputStream zip = new ZipOutputStream(outputStream);

      for (File file : files) {
        byte[] b = new byte[1024];
        int len;
        zip.putNextEntry(new ZipEntry(file.getName()));
        FileInputStream fis = new FileInputStream(file);
        while ((len = fis.read(b)) != -1) {
          zip.write(b, 0, len);
        }

        fis.close();
      }

      zip.flush();
      zip.close();
      outputStream.flush();

      return;
    }

    if (!String.class.isAssignableFrom(retn.getClass())) {
      String mimeType = null;
      Produces prod = this.method.getAnnotation(Produces.class);
      if (prod != null && prod.value() != null && prod.value().length > 0)
        mimeType = prod.value()[0];

      if (mimeType == null || mimeType.trim().length() == 0)
        mimeType =
            this.context.getRequest().getParameter(MVCConfigConstant.HTTP_HEADER_ACCEPT_PARAM);

      if (mimeType == null || mimeType.trim().length() == 0) {
        String contentType = this.context.getRequest().getContentType();
        if (contentType != null) {
          this.context.getResponse().setContentType(contentType);
          mimeType = contentType.split(";")[0];
        }
      }

      if (this.context.getWriter() == null)
        this.context.setWriter(this.context.getResponse().getWriter());

      if (MIMEType.JSON.equals(mimeType) || "json".equalsIgnoreCase(mimeType)) {
        this.context.getResponse().setContentType(MIMEType.JSON);
        this.context.getWriter().print(CommonUtil.toJson(retn));
      } else if (MIMEType.XML.equals(mimeType) || "xml".equalsIgnoreCase(mimeType)) {
        Class<?> cls = retn.getClass();
        if (Collection.class.isAssignableFrom(cls)) {
          Class<?> _cls = ClassUtil.getPojoClass(this.method);
          if (_cls != null) cls = _cls;
        }

        XMLWriter writer = BeanXMLUtil.getBeanXMLWriter(retn);
        writer.setCheckStatck(true);
        writer.setSubNameAuto(true);
        writer.setClass(cls);
        writer.setRootElementName(null);
        this.context.getResponse().setContentType(MIMEType.XML);
        this.context.getWriter().print(writer.toXml());
      } else {
        this.context.getWriter().print("暂时不支持JSON 、XML以外的表述形式");
      }

      this.context.getWriter().flush();

      return;
    }

    List<String> produces = this.context.getActionConfigBean().getProduces();
    if (produces != null && produces.size() > 0)
      for (String produce : produces) {
        this.context.getResponse().setContentType(produce);
        break;
      }

    String re = String.valueOf(retn);

    for (Field f : fields) {
      Method getter = ru.getGetter(f.getName());
      if (getter == null) continue;

      String name = f.getName();
      if (this.context.getModel().containsKey(name)) continue;

      this.context.getModel().put(name, getter.invoke(actionObject));
    }

    this.context.getModel().put(MVCConfigConstant.BASE_URL_KEY, baseUrl);

    // 客户端重定向
    if (re.startsWith(RenderType.REDIRECT + ":")) {
      String url = re.substring((RenderType.REDIRECT + ":").length());
      String location = url;

      this.context.getResponse().sendRedirect(CommonUtil.replaceChinese2Utf8(location));

      return;
    } else if (re.startsWith(RenderType.ACTION + ":")) {
      String path = re.substring((RenderType.ACTION + ":").length());
      // ACTION 重定向
      handleActionRedirect(context, path, baseUrl);

      return;
    } else if (re.startsWith(RenderType.OUT + ":")) {
      String location = re.substring((RenderType.OUT + ":").length());
      this.context.getWriter().print(location);
      this.context.getWriter().flush();

      return;
    } else if (re.startsWith(RenderType.FORWARD + ":")) {
      String location = re.substring((RenderType.FORWARD + ":").length());
      HttpServletRequest request = this.context.getRequest();
      request.setAttribute(MVCConfigConstant.REQ_PARAM_MAP_NAME, this.context.getQueryParamMap());

      for (Iterator<Entry<String, Object>> it = this.context.getModel().entrySet().iterator();
          it.hasNext(); ) {
        Entry<String, Object> entry = it.next();
        request.setAttribute(entry.getKey(), entry.getValue());
      }

      // 服务端跳转
      request
          .getRequestDispatcher(MVCConfigConstant.FORWARD_BASE_PATH + "/" + location)
          .forward(request, this.context.getResponse());

      return;
    } else if (re.startsWith(RenderType.FREEMARKER + ":")) {
      String location = re.substring((RenderType.FREEMARKER + ":").length());
      // FreeMarker 渲染
      Configuration cfg = new Configuration();
      // 指定模板从何处加载的数据源,这里设置成一个文件目录。
      cfg.setDirectoryForTemplateLoading(
          new File(ConfigConstant.ROOT_PATH + MVCConfigConstant.FORWARD_BASE_PATH));
      // 指定模板如何检索数据模型
      cfg.setObjectWrapper(new DefaultObjectWrapper());
      cfg.setDefaultEncoding("utf-8");

      Template template = cfg.getTemplate(location);
      template.setEncoding("utf-8");

      template.process(this.context.getModel(), this.context.getWriter());

      return;
    } else if (re.startsWith(RenderType.VELOCITY + ":")) {
      String location = re.substring((RenderType.VELOCITY + ":").length());
      File viewsDir = new File(ConfigConstant.ROOT_PATH + MVCConfigConstant.FORWARD_BASE_PATH);
      // 初始化Velocity模板引擎
      Properties p = new Properties();
      p.setProperty("resource.loader", "file");
      p.setProperty(
          "file.resource.loader.class",
          "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
      p.setProperty("file.resource.loader.path", viewsDir.getAbsolutePath());
      p.setProperty("file.resource.loader.cache", "true");
      p.setProperty("file.resource.loader.modificationCheckInterval", "2");
      p.setProperty("input.encoding", "utf-8");
      p.setProperty("output.encoding", "utf-8");
      VelocityEngine ve = new VelocityEngine(p);
      // Velocity获取模板文件,得到模板引用
      org.apache.velocity.Template t = ve.getTemplate(location);
      VelocityContext velocityCtx = new VelocityContext();
      for (Iterator<Entry<String, Object>> it = this.context.getModel().entrySet().iterator();
          it.hasNext(); ) {
        Entry<String, Object> e = it.next();
        velocityCtx.put(e.getKey(), e.getValue());
      }

      // 将环境变量和输出部分结合
      t.merge(velocityCtx, this.context.getWriter());
      this.context.getWriter().flush();
      return;
    } else {
      List<ResultConfigBean> results = this.context.getActionConfigBean().getResult();

      if (results == null || results.size() == 0) {
        this.context.getWriter().print(retn);
        this.context.getWriter().flush();
        return;
      }

      boolean isOut = true;
      for (ResultConfigBean r : results) {
        if (!"_props_".equals(r.getName()) && !r.getName().equals(re) && !"".equals(re)) {
          continue;
        }

        isOut = false;
        String type = r.getType();
        String location = r.getLocation();
        if (RenderType.REDIRECT.equalsIgnoreCase(type)) {
          this.context.getResponse().sendRedirect(CommonUtil.replaceChinese2Utf8(location));

          return;
        } else if (RenderType.FORWARD.equalsIgnoreCase(type)) {
          HttpServletRequest request = this.context.getRequest();
          request.setAttribute(
              MVCConfigConstant.REQ_PARAM_MAP_NAME, this.context.getQueryParamMap());

          fields = ru.getFields();
          if (fields == null) return;

          for (Iterator<Entry<String, Object>> it = this.context.getModel().entrySet().iterator();
              it.hasNext(); ) {
            Entry<String, Object> entry = it.next();
            request.setAttribute(entry.getKey(), entry.getValue());
          }
          // 服务端跳转
          request
              .getRequestDispatcher(MVCConfigConstant.FORWARD_BASE_PATH + location)
              .forward(request, this.context.getResponse());

          return;
        } else if (RenderType.FREEMARKER.equalsIgnoreCase(type)) {
          // FreeMarker 渲染
          Configuration cfg = new Configuration();
          // 指定模板从何处加载的数据源,这里设置成一个文件目录。
          cfg.setDirectoryForTemplateLoading(
              new File(ConfigConstant.ROOT_PATH + MVCConfigConstant.FORWARD_BASE_PATH));
          // 指定模板如何检索数据模型
          cfg.setObjectWrapper(new DefaultObjectWrapper());
          cfg.setDefaultEncoding("utf-8");

          Template template = cfg.getTemplate(location);
          template.setEncoding("utf-8");

          template.process(this.context.getModel(), this.context.getWriter());

          return;
        } else if (RenderType.ACTION.equalsIgnoreCase(type)) {
          // ACTION 重定向
          handleActionRedirect(context, location, baseUrl);

          return;
        } else if (RenderType.OUT.equalsIgnoreCase(type) || location.trim().length() == 0) {
          this.context.getWriter().print(location);
          this.context.getWriter().flush();

          return;
        }
      }

      if (isOut) {
        this.context.getWriter().print(retn);
        this.context.getWriter().flush();
      }
    }
  }