@RequestMapping(value = "/tweet/star", method = RequestMethod.POST)
  public void star(
      @RequestParam("uid") long uid,
      @RequestParam("tid") long tid,
      @RequestParam("star") boolean star) {
    Tweet tweet = tweetRepo.findOne(tid);
    if (star) {
      if (userTweetRepo.findByUidAndTidAndUserTweetType(uid, tid, UserTweet.UserTweetType.STAR)
          == null) {
        UserTweet userTweet = new UserTweet();
        userTweet.setUid(uid);
        userTweet.setTid(tid);
        userTweet.setUserTweetType(UserTweet.UserTweetType.STAR);
        userTweetRepo.saveAndFlush(userTweet);

        User user = userRepo.findOne(uid);
        Message message = new Message();
        message.setUid(uid);
        message.setUid2(tweet.getUid());
        message.setTid(tid);
        message.setMessageType(Message.MessageType.STAR);
        message.setTitle(user.getName());
        message.setContent(user.getName());
        message.setIcon(user.getAvatar());
        message.setTime(Utils.getTime());
        message.setDate(System.currentTimeMillis());
        Utils.message(messageRepo.saveAndFlush(message));
      } else {
        return;
      }
    } else {
      userTweetRepo.deleteByUidAndTidAndUserTweetType(uid, tid, UserTweet.UserTweetType.STAR);
    }
    tweet.setStarCount(star ? tweet.getStarCount() + 1 : tweet.getStarCount() - 1);
    tweetRepo.saveAndFlush(tweet);
  }
  // 新建Tweet
  @RequestMapping(value = "/tweet", method = RequestMethod.POST)
  public Tweet add(
      @RequestParam("prompt") String prompt,
      @RequestParam("originTid") long originTid,
      @RequestParam("tweet") MultipartFile tweetFile,
      @RequestParam("image") MultipartFile[] images)
      throws IOException {

    // 保持userTweet
    String tweetJSON = new String(tweetFile.getBytes());
    Tweet tweet = new Gson().fromJson(URLDecoder.decode(tweetJSON, "UTF8"), Tweet.class);
    long uid = tweet.getUid();
    User user = userRepo.findOne(uid);

    if (user.getUserType() == User.UserType.SPECIAL && originTid > 0) { // 超级用户
      Tweet t = tweetRepo.findOne(originTid);
      tweet = new Tweet();
      tweet.setUid(uid);
      tweet.setName(user.getName());
      tweet.setIcon(user.getAvatar());
      tweet.setTweetType(Tweet.TweetType.SPECIAL);
      tweet.setTweetContentType(tweet.getTweetContentType());
      tweet.setTitle(t.getTitle());
      tweet.setSummary(t.getSummary());
      tweet.setImages(t.getImages());
      tweet.setContent(t.getContent());
      tweet.setLat(t.getLat());
      tweet.setLon(t.getLon());
      tweet.setLocation(t.location);
      tweet.setTime(Utils.getTime());
      tweet.setDate(System.currentTimeMillis());
      originTid = 0;
      prompt = null;

    } else {
      String content = tweet.getContent();
      tweet.setSummary(content);
      content = content.replace(" ", "&nbsp;").replace("\n", "<br>");
      Pattern pattern = Pattern.compile("@[^\\p{P}|\\p{S}|\\p{Z}|\\p{M}]*");
      String mContent = content;
      Matcher matcher = pattern.matcher(mContent);
      while (matcher.find()) {
        int start = matcher.start();
        int end = matcher.end();
        String p = mContent.substring(start, end);
        content =
            content.replace(
                p, Constants.TWEET_ADD_PROMPT_HTML.replace(Constants.TWEET_HTML_PROMPT_TAG, p));
      }

      List<String> imageUrls = new ArrayList<>();
      StringBuffer imageContent = new StringBuffer();
      if (images != null) {
        for (MultipartFile image : images) {
          String imageUrl = Utils.image(image);
          if (!StringUtils.isEmpty(imageUrl)) {
            imageUrls.add(imageUrl);
            imageContent.append(
                Constants.TWEET_ADD_IMAGE_HTML.replace(Constants.TWEET_HTML_IMAGE_TAG, imageUrl));
          }
        }
        tweet.setImages(String.join(";", imageUrls));
      }
      tweet.setContent(
          Utils.content(
              Constants.TWEET_ADD_HTML
                  .replace(Constants.TWEET_HTML_CONTENT_TAG, content)
                  .replace(Constants.TWEET_HTML_IMAGES_TAG, imageContent)));
      tweet.setTime(Utils.getTime());
      tweet.setDate(System.currentTimeMillis());
    }

    tweet = tweetRepo.saveAndFlush(tweet);

    UserTweet userTweet = new UserTweet();
    userTweet.setUid(uid);
    userTweet.setTid(tweet.getId());
    userTweet.setUserTweetType(UserTweet.UserTweetType.ADD);
    userTweetRepo.saveAndFlush(userTweet);

    // 保存@ 并且发送message
    if (!StringUtils.isEmpty(prompt)) {
      String[] uids = prompt.split(";");
      for (String id : uids) {
        // 保存@
        UserTweet ut = new UserTweet();
        ut.setUid(Long.valueOf(id));
        ut.setTid(tweet.getId());
        ut.setUserTweetType(UserTweet.UserTweetType.PROMPT);
        userTweetRepo.saveAndFlush(ut);

        // 保存@ message
        Message message = new Message();
        message.setUid(uid);
        message.setUid2(Long.valueOf(id));
        message.setTid(tweet.getId());
        message.setMessageType(Message.MessageType.PROMPT);
        message.setTitle(user.getName());
        message.setContent(user.getName());
        message.setIcon(user.getAvatar());
        message.setTime(Utils.getTime());
        message.setDate(System.currentTimeMillis());
        Utils.message(messageRepo.saveAndFlush(message));
      }
    }

    // 查找转发的tweet
    if (originTid > 0) {
      Tweet originTweet = tweetRepo.findOne(originTid);
      tweet.setOriginTweet(originTweet);
      TweetTweet tweetTweet = new TweetTweet();
      tweetTweet.setTid(tweet.getId());
      tweetTweet.setTid2(originTid);
      tweetTweet.setTweetTweetType(TweetTweet.TweetTweetType.REPEAT);
      tweetTweetRepo.saveAndFlush(tweetTweet);

      originTweet.setRepeatCount(originTweet.getRepeatCount() + 1);
      tweetRepo.saveAndFlush(originTweet);
    }

    return tweet;
  }