package com.xiaozhi.blog.mongo;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.PostConstruct;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.data.redis.support.collections.DefaultRedisList;
import org.springframework.data.redis.support.collections.RedisList;
import org.springframework.stereotype.Repository;
import com.xiaozhi.blog.utils.KeyUtils;
import com.xiaozhi.blog.utils.MentionUtil;
import com.xiaozhi.blog.vo.Comment;
import com.xiaozhi.blog.vo.CommentShow;
import com.xiaozhi.blog.vo.Post;
import com.xiaozhi.blog.vo.Range;
import com.xiaozhi.blog.vo.User;
import com.xiaozhi.blog.vo.WebPost;
@Repository
public class MongoCommentDao {
private static Log logger = LogFactory.getLog(MongoCommentDao.class);
private RedisAtomicLong commentIdCounter;
@Autowired
private MongoOperations mongoTemplate;
@Autowired
private StringRedisTemplate template;
@Autowired
private MongoUserDao mongoUserDao;
@Autowired
private MongoBlogDao blogDao;
@Autowired
private MentionUtil mentionUtil;
@PostConstruct
public void init () {
commentIdCounter = new RedisAtomicLong(KeyUtils.globalPid(), template.getConnectionFactory());
}
/**
* 对微博进行评论
* @param pid
* @param comment
* @param blogOwner 微博对应的拥有者id
* @return
*/
public boolean addComment(final String pid,final Comment comment,final String blogOwner,boolean isReplay) {
final String cid = String.valueOf(commentIdCounter.incrementAndGet());
comment.setCommentId(cid);
if(!isReplay)comment.setTargetBlogId(pid);//评论目标为微博
this.handleMentions(comment);//处理提及@用户的评论
try {
this.mongoTemplate.save(comment);
this.mongoTemplate.updateFirst(new Query(Criteria.where("pid").is(pid)),
new Update().inc("commentNum", 1),Post.class);///对评论数进行+1操作
} catch (Exception e) {
logger.error("==================> addComment mongodb error :"+e.toString());
return false;
}
boolean result = (Boolean) template.execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection)throws DataAccessException {
try {
connection.multi();//事务开启
connection.lPush(KeyUtils.commentByBlog(pid).getBytes(), cid.getBytes());//加入微薄评论列表
connection.lPush(KeyUtils.postComments(comment.getUid()).getBytes(), cid.getBytes());//发出评论列表
//如果不是自己给自己评论则加入收到评论列表
if(!comment.getUid().equals(blogOwner))connection.lPush(KeyUtils.receiveComments(blogOwner).getBytes(), cid.getBytes());
//connection.hIncrBy(KeyUtils.post(pid).getBytes(), "commentNum".getBytes(), 1);//对评论数进行+1操作
connection.exec();
return true;
} catch (Exception e) {
/**callback*/
mongoTemplate.remove(new Query(Criteria.where("commentId").is(comment.getCommentId())),Comment.class);//删除评论对象
mongoTemplate.updateFirst(new Query(Criteria.where("pid").is(Integer.valueOf(pid))),
new Update().inc("commentNum", -1),Post.class);///对评论数进行-1操作
logger.error("==================> addComment error :"+e.toString());
}finally{
connection.close();
}
return false;
}
});
return result;
}
/**
* 删除自己发出的评论的残余
* @param uid
* @param commentId
* @return
*/
public boolean delCommentForNoBlog(final String uid,final String commentId) {
final Comment comment;
try {
comment = this.mongoTemplate.findAndRemove(new Query(Criteria.where("commentId").is(commentId)),Comment.class);//删除评论对象
} catch (Exception e) {
return false;
}
boolean result = (Boolean) template.execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection)throws DataAccessException {
try {
connection.multi();//事务开启
connection.lRem(KeyUtils.postComments(uid).getBytes(), 0, commentId.getBytes());//删除发出的评论
connection.exec();
return true;
} catch (Exception e) {
//call back
mongoTemplate.save(comment);
logger.error("==================> delCommentForNoBlog error :"+e.toString());
}finally{
connection.close();
}
return false;
}
});
return result;
}
/**
* 删除微博评论
* @param name
* @param userid
* @return
*/
public boolean removeComment(final String pid,final String commentId,final String uid,final String blogOwner){
final Comment comment;
try {
comment = this.mongoTemplate.findAndRemove(new Query(Criteria.where("commentId").is(commentId)),Comment.class);//删除评论对象
this.mongoTemplate.updateFirst(new Query(Criteria.where("pid").is(pid)),new Update().inc("commentNum", -1),Post.class);//对评论数进行-1操作
} catch (Exception e) {
return false;
}
boolean result = (Boolean) template.execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection)throws DataAccessException {
try {
connection.multi();//事务开启
connection.lRem(KeyUtils.commentByBlog(pid).getBytes(), 0, commentId.getBytes());//删除微薄对应评论Id
connection.lRem(KeyUtils.postComments(uid).getBytes(), 0, commentId.getBytes());//删除发出的评论
if(!uid.equals(blogOwner))connection.lRem(KeyUtils.receiveComments(blogOwner).getBytes(), 0, commentId.getBytes());//删除收到的评论
connection.exec();
return true;
} catch (Exception e) {
//call back
mongoTemplate.save(comment);
mongoTemplate.updateFirst(new Query(Criteria.where("pid").is(pid)),new Update().inc("commentNum", 1),Post.class);//对评论数进行+1操作
logger.error("==================> removeComment error :"+e.toString());
}finally{
connection.close();
}
return false;
}
});
return result;
}
/**
* 获得一条微博的评论列表
* @param pid
* @param userid
* @return
*/
public List<CommentShow> getCommentListByPid(String pid,final String userid){
List<String> keys = this.template.opsForList().range(KeyUtils.commentByBlog(pid), 0,-1);
Query query = new Query(Criteria.where("commentId").in(keys.toArray()));
//query.sort().on("time",Order.DESCENDING);//按时间倒序
query.with(new Sort(Sort.Direction.DESC,"time"));//按时间倒序
List<Comment> comments = this.mongoTemplate.find(query,Comment.class);
List<CommentShow> commentShows = new ArrayList<CommentShow>();
List<String> uids = new ArrayList<String>();//定义当前微博评论所有用户id集合
for(Comment comment :comments){
CommentShow commentShow = new CommentShow();
commentShow.setContent(comment.getContent());
commentShow.setTime(comment.getTime());
commentShow.setCommentId(Integer.valueOf(comment.getCommentId()));
commentShow.setUid(comment.getUid());
commentShow.setCanDelete(comment.getUid().equals(userid)?true:false);
commentShow.initTimeShow();//初始化时间显示
uids.add(comment.getUid());
commentShows.add(commentShow);
}
Map<String, User> userMap = this.mongoUserDao.getUsersByIds(uids);
for(CommentShow comment: commentShows){
comment.setUser(userMap.get(comment.getUid()));
}
return commentShows;
}
/**
* 获得用户的评论列表
* @param uid
* @return
*/
public List<CommentShow> getCommentList(final String uid,List<String> keys,Range range){
List<String> pagekeysList=keys.subList(range.being, (range.end+1)>keys.size()?keys.size():(range.end+1));
List<Comment> comments = this.mongoTemplate.find(new Query(Criteria.where("commentId").in(pagekeysList.toArray())),Comment.class);
Map<String,CommentShow> commentShows = new ConcurrentHashMap<String,CommentShow>();
List<CommentShow> returnShow = new ArrayList<CommentShow>();
List<String> pids= new ArrayList<String>();
List<String> uids = new ArrayList<String>();//定义当前页所有用户id集合
for(Comment comment :comments){
CommentShow commentShow = new CommentShow();
commentShow.setContent(comment.getContent());
commentShow.setTime(comment.getTime());
commentShow.setCommentId(Integer.valueOf(comment.getCommentId()));
commentShow.setTargetBlogId(comment.getTargetBlogId());
commentShow.setUid(comment.getUid());
commentShow.setCanDelete(comment.getUid().equals(uid)?true:false);
commentShow.initTimeShow();//初始化时间显示
commentShows.put(comment.getCommentId(),commentShow);
uids.add(comment.getUid());
pids.add(comment.getTargetBlogId());
}
//将用户信息和对应微博添加进去
Map<String, User> userMap = this.mongoUserDao.getUsersByIds(uids);
Map<String,WebPost> websMap = this.blogDao.convertrelayPidsToPosts(pids);
for(String key :pagekeysList){
CommentShow commentShow = new CommentShow();
commentShow.setCommentId(Integer.valueOf(key));
CommentShow show=commentShows.get(key);
if(show!=null){
show.setUser(userMap.get(show.getUid()));
show.setWebPost(websMap.get(show.getTargetBlogId()));
returnShow.add(show);
}else{
returnShow.add(commentShow);
}
}
return returnShow;
}
/**
* 用户的评论数
* @param uid
* @return
*/
public List<String> getCommentListNum(String uid,String key){
return this.template.opsForList().range(key, 0,-1);
}
/**
* 处理提及@用户的事宜
* @param post
* @param pid
*/
private void handleMentions(Comment comment) {
// find mentions
List<String> mentions = mentionUtil.findMentions(comment.getContent());
comment.setContent(mentionUtil.replaceMentions(comment.getContent()));
Map<String, User> map = this.mongoUserDao.getUsersByNickNames(mentions);
for (String mention : mentions) {
User user = map.get(mention);
if (user != null) {
commentmentions(user.getId()).addFirst(comment.getCommentId().toString());
}
}
}
private RedisList<String> commentmentions(String uid) {
return new DefaultRedisList<String>(KeyUtils.commentmentions(uid), template);
}
}