Commit e80fc01a authored by 刘基明's avatar 刘基明

热点数据批量查询db

parent 2b840e51
package com.tanpu.community.dao.entity.community;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class TimesCountEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "次数")
private Integer times;
@ApiModelProperty(value = "目标id")
private String id;
}
package com.tanpu.community.dao.mapper.community;
import com.tanpu.community.dao.entity.community.CollectionEntity;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.tanpu.community.dao.entity.community.CollectionEntity;
import com.tanpu.community.dao.entity.community.TimesCountEntity;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* <p>
......@@ -13,4 +20,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface CollectionMapper extends BaseMapper<CollectionEntity> {
@Select("select target_id as id, count(1) as times from collection ${ew.customSqlSegment}")
List<TimesCountEntity> selectCountByTargetIds(@Param(Constants.WRAPPER) LambdaQueryWrapper wrapper);
}
package com.tanpu.community.dao.mapper.community;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.tanpu.community.dao.entity.community.CommentEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tanpu.community.dao.entity.community.TimesCountEntity;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* <p>
......@@ -13,4 +20,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface CommentMapper extends BaseMapper<CommentEntity> {
@Select("select theme_id as id, count(1) as times from comment ${ew.customSqlSegment}")
List<TimesCountEntity> selectCountByThemeIds(@Param(Constants.WRAPPER) LambdaQueryWrapper wrapper);
}
package com.tanpu.community.dao.mapper.community;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.tanpu.community.dao.entity.community.ThemeEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tanpu.community.dao.entity.community.TimesCountEntity;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* <p>
......@@ -13,4 +20,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface ThemeMapper extends BaseMapper<ThemeEntity> {
@Select("select former_theme_id as id, count(1) as times from theme ${ew.customSqlSegment}")
List<TimesCountEntity> selectCountByThemeIds(@Param(Constants.WRAPPER) LambdaQueryWrapper wrapper);
}
package com.tanpu.community.dao.mapper.community;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.tanpu.community.dao.entity.community.TimesCountEntity;
import com.tanpu.community.dao.entity.community.VisitSummaryEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
......@@ -25,4 +28,7 @@ public interface VisitSummaryMapper extends BaseMapper<VisitSummaryEntity> {
@Select("select ref_id from visit_summary where visitor_id=#{visitorId} and ref_id in (#{refIds})")
List<String> selectRefIdByUserId(@Param("visitorId") String visitorId, @Param("refIds") String refIds);
@Select("select ref_id as id, count(1) as times from visit_summary ${ew.customSqlSegment}")
List<TimesCountEntity> selectCountByThemeIds(@Param(Constants.WRAPPER)LambdaQueryWrapper wrapper);
}
......@@ -109,7 +109,7 @@ public class CommentManager {
//点赞评论/取消点赞
public void likeComment(LikeCommentReq req, String userId) {
if (OperationTypeEnum.CONFIRM.getCode().equals(req.getType())) {
collectionService.addIfNotExist(req.getCommentId(), userId, CollectionTypeEnum.LIKE_COMMENT);
collectionService.saveOrUpdate(req.getCommentId(), userId, CollectionTypeEnum.LIKE_COMMENT);
} else if (OperationTypeEnum.CANCEL.getCode().equals(req.getType())) {
collectionService.delete(req.getCommentId(), userId, CollectionTypeEnum.LIKE_COMMENT);
}
......
......@@ -320,7 +320,7 @@ public class ThemeManager {
// 点赞/取消点赞
public void like(LikeThemeReq req, String userId) {
if (OperationTypeEnum.CONFIRM.getCode().equals(req.getType())) {
collectionService.addIfNotExist(req.getThemeId(), userId, CollectionTypeEnum.LIKE_THEME);
collectionService.saveOrUpdate(req.getThemeId(), userId, CollectionTypeEnum.LIKE_THEME);
} else if (OperationTypeEnum.CANCEL.getCode().equals(req.getType())) {
collectionService.delete(req.getThemeId(), userId, CollectionTypeEnum.LIKE_THEME);
}
......@@ -330,7 +330,7 @@ public class ThemeManager {
//收藏/取消收藏
public void collect(CollectThemeReq req, String userId) {
if (OperationTypeEnum.CONFIRM.getCode().equals(req.getType())) {
collectionService.addIfNotExist(req.getThemeId(), userId, CollectionTypeEnum.COLLECT_THEME);
collectionService.saveOrUpdate(req.getThemeId(), userId, CollectionTypeEnum.COLLECT_THEME);
} else if (OperationTypeEnum.CANCEL.getCode().equals(req.getType())) {
collectionService.delete(req.getThemeId(), userId, CollectionTypeEnum.COLLECT_THEME);
}
......
......@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tanpu.community.api.enums.CollectionTypeEnum;
import com.tanpu.community.api.enums.DeleteTagEnum;
import com.tanpu.community.dao.entity.community.CollectionEntity;
import com.tanpu.community.dao.entity.community.TimesCountEntity;
import com.tanpu.community.dao.mapper.community.CollectionMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
......@@ -11,6 +12,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
......@@ -22,7 +24,7 @@ public class CollectionService {
// 若不存在则新增,若存在则修改deleteTag
@Transactional
public void addIfNotExist(String themeId, String userId, CollectionTypeEnum type) {
public void saveOrUpdate(String themeId, String userId, CollectionTypeEnum type) {
// 判断记录是否存在,无论是否删除
CollectionEntity queryCollection = getTargetCollection(themeId, userId, type);
if (queryCollection != null) {
......@@ -64,7 +66,7 @@ public class CollectionService {
// 根据用户id和行为type获取target_id列表
public Set<String> getListByUser(String userId, CollectionTypeEnum type) {
return collectionMapper.selectList(new LambdaQueryWrapper<CollectionEntity>()
.eq(CollectionEntity::getUserId,userId)
.eq(CollectionEntity::getUserId, userId)
.eq(CollectionEntity::getCollectionType, type.getCode())
.eq(CollectionEntity::getDeleteTag, DeleteTagEnum.NOT_DELETED.getCode()))
.stream().map(CollectionEntity::getTargetId).collect(Collectors.toSet());
......@@ -79,6 +81,15 @@ public class CollectionService {
.eq(CollectionEntity::getDeleteTag, DeleteTagEnum.NOT_DELETED.getCode())));
}
// 统计多个对象(主题、评论)的数量(点赞、收藏)
public Map<String, Integer> getCountMapByType(List<String> targetIds, CollectionTypeEnum type) {
LambdaQueryWrapper<CollectionEntity> queryWrapper = new LambdaQueryWrapper<CollectionEntity>().eq(CollectionEntity::getCollectionType, 1)
.in(CollectionEntity::getTargetId, targetIds).groupBy(CollectionEntity::getTargetId);
return collectionMapper.selectCountByTargetIds(queryWrapper).stream()
.collect(Collectors.toMap(TimesCountEntity::getId, TimesCountEntity::getTimes));
}
// 统计多个对象(主题、评论)的数量(点赞、收藏)
public Integer getCountByTypeAndIds(List<String> targetIds, CollectionTypeEnum type) {
return collectionMapper.selectCount((new LambdaQueryWrapper<CollectionEntity>()
......@@ -86,6 +97,7 @@ public class CollectionService {
.eq(CollectionEntity::getCollectionType, type.getCode()))
.eq(CollectionEntity::getDeleteTag, DeleteTagEnum.NOT_DELETED.getCode()));
}
//逻辑删除,修改delete_tag
@Transactional
public void delete(String themeId, String userId, CollectionTypeEnum type) {
......
......@@ -9,6 +9,7 @@ import com.tanpu.community.api.enums.DeleteTagEnum;
import com.tanpu.community.api.enums.ReportStatusEnum;
import com.tanpu.community.cache.RedisCache;
import com.tanpu.community.dao.entity.community.CommentEntity;
import com.tanpu.community.dao.entity.community.TimesCountEntity;
import com.tanpu.community.dao.mapper.community.CommentMapper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
......@@ -18,7 +19,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.stream.Collectors;
import static com.tanpu.community.api.constants.RedisKeyConstant.CACHE_COMMENT_THEMEID;
......@@ -51,47 +52,46 @@ public class CommentService {
}
//统计主题集合的评论量
public Integer getCommentCountByThemeIds(List<String> themeIds) {
if (CollectionUtils.isEmpty(themeIds)){
public Integer getTotalCountByThemeIds(List<String> themeIds) {
if (CollectionUtils.isEmpty(themeIds)) {
return 0;
}
return commentMapper.selectList((new LambdaQueryWrapper<CommentEntity>()
return commentMapper.selectList((new LambdaQueryWrapper<CommentEntity>()
.in(CommentEntity::getThemeId, themeIds)))
.size();
}
//统计主题集合的评论量
public Integer getCommentCountByThemeId(String themeId) {
return commentMapper.selectList((new LambdaQueryWrapper<CommentEntity>()
return commentMapper.selectList((new LambdaQueryWrapper<CommentEntity>()
.eq(CommentEntity::getThemeId, themeId)))
.size();
}
public Set<String> getCommentUserCount(List<String> themeIds) {
return commentMapper.selectList((new LambdaQueryWrapper<CommentEntity>()
.in(CommentEntity::getThemeId, themeIds)))
.stream().map(CommentEntity::getAuthorId).collect(Collectors.toSet());
//统计主题集合的评论量
public Map<String, Integer> getCountMapByThemeIds(List<String> themeIds) {
LambdaQueryWrapper<CommentEntity> wrapper = (new LambdaQueryWrapper<CommentEntity>()
.in(CommentEntity::getThemeId, themeIds))
.eq(CommentEntity::getDeleteTag, DeleteTagEnum.NOT_DELETED)
.groupBy(CommentEntity::getThemeId);
return commentMapper.selectCountByThemeIds(wrapper).stream()
.collect(Collectors.toMap(TimesCountEntity::getId, TimesCountEntity::getTimes));
}
public List<CommentEntity> selectByThemeId(String themeId) {
return redisCache.getList(StringUtils.joinWith("_", CACHE_COMMENT_THEMEID, themeId),
60, () -> {
LambdaQueryWrapper<CommentEntity> queryWrapper = new LambdaQueryWrapper<CommentEntity>()
.eq(CommentEntity::getThemeId, themeId)
.eq(CommentEntity::getDeleteTag, DeleteTagEnum.NOT_DELETED.getCode())
.orderByDesc(CommentEntity::getCreateTime);
return commentMapper.selectList(queryWrapper);
}, new TypeReference<List<CommentEntity>>() {});
LambdaQueryWrapper<CommentEntity> queryWrapper = new LambdaQueryWrapper<CommentEntity>()
.eq(CommentEntity::getThemeId, themeId)
.eq(CommentEntity::getDeleteTag, DeleteTagEnum.NOT_DELETED.getCode())
.orderByDesc(CommentEntity::getCreateTime);
return commentMapper.selectList(queryWrapper);
}, new TypeReference<List<CommentEntity>>() {
});
}
public List<CommentEntity> queryCommentsByUserId(String userId) {
return commentMapper.selectList(new LambdaQueryWrapper<CommentEntity>()
.eq(CommentEntity::getAuthorId,userId)
.eq(CommentEntity::getCommentType, CommentTypeEnum.THEME.getCode())
.eq(CommentEntity::getDeleteTag,DeleteTagEnum.NOT_DELETED.getCode()));
}
public List<CommentEntity> queryCommentsByUserId(String userId, String lastId, Integer pageSize) {
LambdaQueryWrapper<CommentEntity> queryWrapper = new LambdaQueryWrapper<CommentEntity>()
......@@ -101,20 +101,20 @@ public class CommentService {
.orderByDesc(CommentEntity::getCreateTime);
if (StringUtils.isNotEmpty(lastId)) {
CommentEntity commentEntity = commentMapper.selectOne(new LambdaQueryWrapper<CommentEntity>()
.eq(CommentEntity::getCommentId,lastId));
if (commentEntity==null) throw new BizException("评论未找到,id:"+lastId);
.eq(CommentEntity::getCommentId, lastId));
if (commentEntity == null) throw new BizException("评论未找到,id:" + lastId);
queryWrapper.lt(CommentEntity::getUpdateTime, commentEntity.getCreateTime());
}
if (pageSize!=null){
queryWrapper.last("limit "+pageSize);
if (pageSize != null) {
queryWrapper.last("limit " + pageSize);
}
return commentMapper.selectList(queryWrapper);
}
public void updateReportStatus(String commentId) {
CommentEntity commentEntity = queryByCommentId(commentId);
if (commentEntity==null){
throw new BizException("评论未找到,id:"+commentId);
if (commentEntity == null) {
throw new BizException("评论未找到,id:" + commentId);
}
commentEntity.setReportStatus(ReportStatusEnum.REPORTED.getCode());
commentMapper.updateById(commentEntity);
......
......@@ -7,6 +7,7 @@ import com.tanpu.community.api.beans.qo.TopicRankQo;
import com.tanpu.community.api.beans.vo.feign.fatools.UserInfoNew;
import com.tanpu.community.api.enums.CollectionTypeEnum;
import com.tanpu.community.api.enums.TopicStatusEnum;
import com.tanpu.community.api.enums.VisitTypeEnum;
import com.tanpu.community.cache.RedisCache;
import com.tanpu.community.dao.entity.community.ThemeEntity;
import com.tanpu.community.dao.entity.community.TopicEntity;
......@@ -57,13 +58,20 @@ public class RankService {
//7天内所有主题进行热度值排序
List<ThemeEntity> themeEntities = themeService.queryRecentdays(7);
List<ThemeAnalysDO> themeAnalysDOS = ConvertUtil.themeEntityToAnalysDOs(themeEntities);
//批量查询
List<String> themeIds = themeAnalysDOS.stream().map(ThemeAnalysDO::getThemeId).collect(Collectors.toList());
Map<String, Integer> likeCountMap = collectionService.getCountMapByType(themeIds, CollectionTypeEnum.LIKE_THEME);
Map<String, Integer> bookCountMap = collectionService.getCountMapByType(themeIds, CollectionTypeEnum.COLLECT_THEME);
Map<String, Integer> commentCountMap = commentService.getCountMapByThemeIds(themeIds);
Map<String, Integer> forwardCountMap = themeService.getForwardCountMap(themeIds);
Map<String, Integer> visitCountMap = visitSummaryService.getCountMapByThemeIds(themeIds, VisitTypeEnum.THEME_PAGE_VIEW);
for (ThemeAnalysDO theme : themeAnalysDOS) {
String themeId = theme.getThemeId();
Integer likeCount = collectionService.getCountByTypeAndId(themeId, CollectionTypeEnum.LIKE_THEME);
Integer bookCount = collectionService.getCountByTypeAndId(themeId, CollectionTypeEnum.COLLECT_THEME);
Integer commentCount = commentService.getCommentCountByThemeId(themeId);
Integer forwardCount = themeService.getForwardCountById(themeId);
Integer viewCount = visitSummaryService.queryThemeVisit(themeId);
Integer likeCount = likeCountMap.getOrDefault(themeId, 0);
Integer bookCount = bookCountMap.getOrDefault(themeId,0);
Integer commentCount = commentCountMap.getOrDefault(themeId,0);
Integer forwardCount = forwardCountMap.getOrDefault(themeId,0);
Integer viewCount = visitCountMap.getOrDefault(themeId,0);
theme.setCommentCount(commentCount);
theme.setLikeCount(likeCount);
theme.setForwardCount(forwardCount);
......@@ -120,7 +128,7 @@ public class RankService {
Integer themePV = visitSummaryService.queryThemeVisit(themeIds);
topic.setViewCount(topicPV + themePV);
//讨论数=发布主题贴数+回复总数
Integer commentCount = commentService.getCommentCountByThemeIds(themeIds);
Integer commentCount = commentService.getTotalCountByThemeIds(themeIds);
topic.setDisscussCount(themeIds.size() + commentCount);
}
Map<TopicRankQo, Integer> map = topicRankQos.stream().collect(Collectors.toMap(o -> o, TopicRankQo::getRank));
......@@ -170,11 +178,11 @@ public class RankService {
if (this.rankTopicList.size() == 0) {
this.rankTopics();
}
if (StringUtils.isEmpty(keyword)){
if (StringUtils.isEmpty(keyword)) {
return rankTopicList;
}else {
} else {
//过滤关键字
return this.rankTopicList.stream().filter(o->o.getTopicTitle().contains(keyword)).collect(Collectors.toList());
return this.rankTopicList.stream().filter(o -> o.getTopicTitle().contains(keyword)).collect(Collectors.toList());
}
}
......@@ -200,4 +208,5 @@ public class RankService {
.map(ThemeAnalysDO::getThemeId)
.collect(Collectors.toList());
}
}
......@@ -8,6 +8,7 @@ import com.tanpu.common.uuid.UuidGenHelper;
import com.tanpu.community.api.enums.DeleteTagEnum;
import com.tanpu.community.api.enums.ReportStatusEnum;
import com.tanpu.community.dao.entity.community.ThemeEntity;
import com.tanpu.community.dao.entity.community.TimesCountEntity;
import com.tanpu.community.dao.mapper.community.ThemeMapper;
import com.tanpu.community.util.TimeUtils;
import org.apache.commons.collections4.CollectionUtils;
......@@ -20,7 +21,7 @@ import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.stream.Collectors;
@Service
......@@ -197,8 +198,6 @@ public class ThemeService {
}
/**
* 根据话题查询最新主题(可分页)
*
......@@ -234,7 +233,6 @@ public class ThemeService {
return themeMapper.selectList(queryWrapper).stream().map(ThemeEntity::getThemeId).collect(Collectors.toList());
}
/**
* 根据作者查询主题列表(可分页)
*
......@@ -258,40 +256,6 @@ public class ThemeService {
}
/**
* 根据关键字搜索
*
* @param keyword
* @param lastId
* @param pageSize
* @return
*/
public List<ThemeEntity> search(String keyword, String lastId, Integer pageSize) {
if (StringUtils.isEmpty(keyword)) {
return Collections.emptyList();
}
LambdaQueryWrapper<ThemeEntity> queryWrapper = new LambdaQueryWrapper<ThemeEntity>()
.like(ThemeEntity::getTitle, keyword);
if (StringUtils.isNotEmpty(lastId)) {
ThemeEntity lastEntity = queryByThemeId(lastId);
if (lastEntity == null) throw new BizException("主题未找到,id:" + lastId);
queryWrapper.lt(ThemeEntity::getUpdateTime, lastEntity.getCreateTime());
}
queryWrapper.last("limit " + pageSize);
queryWrapper.orderByDesc(ThemeEntity::getCreateTime);
queryWrapper.eq(ThemeEntity::getDeleteTag, DeleteTagEnum.NOT_DELETED.getCode());
return themeMapper.selectList(queryWrapper);
}
//查询对应话题的发表用户集合
public Set<String> getPostUserCount(List<String> themeIds) {
return themeMapper.selectBatchIds(themeIds).stream()
.map(ThemeEntity::getAuthorId)
.collect(Collectors.toSet());
}
public Integer getForwardCountById(String themeId) {
return themeMapper.selectCount(new LambdaQueryWrapper<ThemeEntity>()
.eq(ThemeEntity::getFormerThemeId, themeId)
......@@ -345,4 +309,15 @@ public class ThemeService {
themeEntity.setReportStatus(ReportStatusEnum.REPORTED.getCode());
themeMapper.updateById(themeEntity);
}
//统计主题集合的浏览量
public Map<String, Integer> getForwardCountMap(List<String> themeIds) {
LambdaQueryWrapper<ThemeEntity> wrapper = new LambdaQueryWrapper<ThemeEntity>()
.eq(ThemeEntity::getDeleteTag, DeleteTagEnum.NOT_DELETED)
.in(ThemeEntity::getFormerThemeId,themeIds)
.groupBy(ThemeEntity::getFormerThemeId);
return themeMapper.selectCountByThemeIds(wrapper).stream()
.collect(Collectors.toMap(TimesCountEntity::getId, TimesCountEntity::getTimes));
}
}
package com.tanpu.community.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanpu.community.api.enums.DeleteTagEnum;
import com.tanpu.community.api.enums.VisitTypeEnum;
import com.tanpu.community.dao.entity.community.TimesCountEntity;
import com.tanpu.community.dao.entity.community.VisitSummaryEntity;
import com.tanpu.community.dao.mapper.community.VisitSummaryMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
......@@ -89,4 +90,15 @@ public class VisitSummaryService {
return visitSummaryEntities.get(0).getCreateTime();
}
}
//统计主题集合的浏览量
public Map<String, Integer> getCountMapByThemeIds(List<String> themeIds,VisitTypeEnum type) {
LambdaQueryWrapper<VisitSummaryEntity> wrapper = (new LambdaQueryWrapper<VisitSummaryEntity>()
.in(VisitSummaryEntity::getRefId,themeIds))
.eq(VisitSummaryEntity::getDeleteTag, DeleteTagEnum.NOT_DELETED)
.eq(VisitSummaryEntity::getRefType,type.getCode())
.groupBy(VisitSummaryEntity::getRefId);
return visitSummaryMapper.selectCountByThemeIds(wrapper).stream()
.collect(Collectors.toMap(TimesCountEntity::getId, TimesCountEntity::getTimes));
}
}
......@@ -15,4 +15,11 @@
<result column="delete_tag" property="deleteTag" />
</resultMap>
<resultMap id="CountResultMap" type="com.tanpu.community.dao.entity.community.TimesCountEntity">
<id column="id" property="id" />
<result column="collection_type" property="collectionType" />
<result column="target_id" property="targetId" />
<result column="times" property="times" />
</resultMap>
</mapper>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment