protected void attachmentDownload(T entity, String attachmentId) {
    try {
      AttachmentFileService attachmentFileService =
          SpringContextHolder.getBean(AttachmentFileService.class);
      AttachmentFile attachmentFile = attachmentFileService.findOne(attachmentId);
      if (attachmentFile != null
          && entity.getId().toString().equals(attachmentFile.getEntityId())
          && entity.getClass().getName().equals(attachmentFile.getEntityClassName())) {
        HttpServletResponse response = ServletActionContext.getResponse();
        ServletUtils.setFileDownloadHeader(response, attachmentFile.getFileRealName());
        response.setContentType(attachmentFile.getFileType());

        DynamicConfigService dynamicConfigService =
            SpringContextHolder.getBean(DynamicConfigService.class);
        String rootPath = dynamicConfigService.getFileUploadRootDir();
        File diskFile =
            new File(
                rootPath
                    + attachmentFile.getFileRelativePath()
                    + File.separator
                    + attachmentFile.getDiskFileName());
        logger.debug("Downloading attachment file from disk: {}", diskFile.getAbsolutePath());
        ServletUtils.renderFileDownload(response, FileUtils.readFileToByteArray(diskFile));
      }
    } catch (Exception e) {
      logger.error("Download file error", e);
    }
  }
  @MetaData(value = "保存")
  protected HttpHeaders doSave() {
    getEntityService().save(bindingEntity);

    // 附件关联处理,自动处理以attachment为前缀的参数
    if (bindingEntity instanceof AttachmentableEntity) {
      Enumeration<?> names = getRequest().getParameterNames();
      Set<String> attachmentNames = Sets.newHashSet();
      while (names.hasMoreElements()) {
        String name = (String) names.nextElement();
        if (name.startsWith("_attachment_")) {
          attachmentNames.add(name);
        }
      }
      if (attachmentNames.size() > 0) {
        AttachmentFileService attachmentFileService =
            SpringContextHolder.getBean(AttachmentFileService.class);
        for (String attachmentName : attachmentNames) {
          String[] attachments = getParameterIds(attachmentName);
          attachmentFileService.attachmentBind(
              attachments,
              bindingEntity,
              StringUtils.substringAfter(attachmentName, "_attachment_"));
        }
      }
    }
    setModel(OperationResult.buildSuccessResult("数据保存成功", bindingEntity));
    return buildDefaultHttpHeaders();
  }
  protected HttpHeaders attachmentList(T entity, String category) {
    HttpServletRequest request = getRequest();
    String url = request.getServletPath();
    AttachmentFileService attachmentFileService =
        SpringContextHolder.getBean(AttachmentFileService.class);
    List<AttachmentFile> attachmentFiles =
        attachmentFileService.findBy(
            entity.getClass().getName(), String.valueOf(entity.getId()), category);
    List<Map<String, Object>> filesResponse = Lists.newArrayList();
    for (AttachmentFile attachmentFile : attachmentFiles) {
      Map<String, Object> dataMap = Maps.newHashMap();
      dataMap.put("id", attachmentFile.getId());
      dataMap.put("attachmentName", "_attachment_" + attachmentFile.getEntityFileCategory());
      dataMap.put("name", attachmentFile.getFileRealName());
      dataMap.put("size", FileUtils.byteCountToDisplaySize(attachmentFile.getFileLength()));

      dataMap.put(
          "url",
          getRequest().getContextPath()
              + StringUtils.substringBefore(url, "!attachmentList")
              + "!attachmentDownload?id="
              + entity.getId()
              + "&attachmentId="
              + attachmentFile.getId());
      filesResponse.add(dataMap);
    }
    Map<String, List<Map<String, Object>>> response = Maps.newHashMap();
    response.put("files", filesResponse);
    setModel(response);
    return buildDefaultHttpHeaders();
  }
  @Override
  public void contextDestroyed(ServletContextEvent sce) {
    // 在容器销毁时把未正常结束遗留的登录记录信息强制设置登出时间
    logger.info("ServletContext destroy force setup session user logout time...");

    UserLogonLogService userLogonLogService =
        SpringContextHolder.getBean(UserLogonLogService.class);
    GroupPropertyFilter groupPropertyFilter = new GroupPropertyFilter();
    groupPropertyFilter.and(new PropertyFilter(MatchType.NU, "logoutTime", Boolean.TRUE));
    List<UserLogonLog> userLogonLogs = userLogonLogService.findByFilters(groupPropertyFilter);
    if (!CollectionUtils.isEmpty(userLogonLogs)) {

      Set<String> sessionIdSet = new HashSet<String>();
      SessionRegistry sessionRegistry = SpringContextHolder.getBean(SessionRegistry.class);
      List<Object> principals = sessionRegistry.getAllPrincipals();
      for (Object principal : principals) {
        List<SessionInformation> sessionInformations =
            sessionRegistry.getAllSessions(principal, true);
        for (SessionInformation sessionInformation : sessionInformations) {
          sessionIdSet.add(sessionInformation.getSessionId());
        }
      }
      Date now = new Date();
      Date yesterday = new DateTime().minusDays(1).toDate();
      for (UserLogonLog userLogonLog : userLogonLogs) {
        if (userLogonLog.getLogonTime().before(yesterday)) {
          Date logoutTime = new DateTime(userLogonLog.getLogonTime()).plusHours(1).toDate();
          userLogonLog.setLogoutTime(logoutTime);
        } else {
          if (sessionIdSet.contains(userLogonLog.getHttpSessionId())) {
            userLogonLog.setLogoutTime(now);
          } else {
            continue;
          }
        }
        logger.debug(" - Setup logout time for session ID: {}", userLogonLog.getHttpSessionId());
        userLogonLog.setLogonTimeLength(
            userLogonLog.getLogoutTime().getTime() - userLogonLog.getLogonTime().getTime());
        userLogonLogService.save(userLogonLog);
      }
    }
  }
 @Override
 public void sessionDestroyed(HttpSessionEvent se) {
   HttpSession session = se.getSession();
   String sessionId = session.getId();
   UserLogonLogService userLogonLogService =
       SpringContextHolder.getBean(UserLogonLogService.class);
   UserLogonLog userLogonLog = userLogonLogService.findBySessionId(sessionId);
   if (userLogonLog != null) {
     logger.debug("Setup logout time for session ID: {}", sessionId);
     userLogonLog.setLogoutTime(new Date());
     userLogonLog.setLogonTimeLength(
         userLogonLog.getLogoutTime().getTime() - userLogonLog.getLogonTime().getTime());
     userLogonLogService.save(userLogonLog);
   }
 }