1. 帖子作者发布帖子,帖子标题可以为空,帖子内容不能为空,且不少于16个汉字;
2. 帖子可以加入不多于五个话题,且话题不能重复加入; 3. 帖子标题和内容通过内容过滤后方能发布,如果未能通过内容过滤,则需要经过运营审核之后才能发布。
This commit is contained in:
parent
a18783fca4
commit
6d4d53054d
99
src/main/java/cn/allms/community/domain/model/post/Post.java
Normal file
99
src/main/java/cn/allms/community/domain/model/post/Post.java
Normal file
@ -0,0 +1,99 @@
|
||||
package cn.allms.community.domain.model.post;
|
||||
|
||||
import cn.allms.community.domain.model.topic.TopicPost;
|
||||
import cn.allms.community.infrastructure.constant.CommonConstants;
|
||||
import cn.allms.community.infrastructure.constant.ExceptionCodeConstant;
|
||||
import cn.allms.community.infrastructure.exception.BusinessException;
|
||||
import lombok.Data;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 帖子对象
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 11:50
|
||||
*/
|
||||
@Data
|
||||
public class Post {
|
||||
/**
|
||||
* 帖子ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 帖子作者ID
|
||||
*/
|
||||
private Long authorId;
|
||||
|
||||
/**
|
||||
* 帖子标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 帖子内容
|
||||
*/
|
||||
private String sourceContent;
|
||||
|
||||
/**
|
||||
* 发帖时间戳
|
||||
*/
|
||||
private Long postingTime;
|
||||
|
||||
/**
|
||||
* 最后修改时间
|
||||
*/
|
||||
private Long lastModifyTime;
|
||||
|
||||
/**
|
||||
* 加入的话题
|
||||
*/
|
||||
private Set<TopicPost> topics = new HashSet<>();
|
||||
|
||||
/**
|
||||
* 最多加入的主题数
|
||||
*/
|
||||
public static final Integer MAX_JOINED_TOPICS_NUM = 5;
|
||||
|
||||
/**
|
||||
* 自定义的setter,优先会调用此set方法,而不是lombok自带的
|
||||
* @param authorId 作者Id
|
||||
*/
|
||||
public void setAuthorId(Long authorId) {
|
||||
Assert.isTrue(authorId > 0, "帖子作者Id必须大于0");
|
||||
this.authorId = authorId;
|
||||
}
|
||||
|
||||
public void setSourceContent(String sourceContent) {
|
||||
Assert.isTrue(Objects.nonNull(sourceContent), "帖子内容不能为空");
|
||||
Assert.isTrue(sourceContent.length() >= 16, "帖子内容必须大于16");
|
||||
this.sourceContent = sourceContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将帖子关联话题 | 加入话题
|
||||
*
|
||||
* @param topicIds 话题集合
|
||||
*/
|
||||
public void joinTopics(String topicIds) throws BusinessException {
|
||||
if (Objects.isNull(topicIds)) {
|
||||
return;
|
||||
}
|
||||
String[] topicIdArray = topicIds.split(CommonConstants.TOPIC_SPLIT_COMMA);
|
||||
for (String s : topicIdArray) {
|
||||
TopicPost topicPost = new TopicPost(Long.valueOf(s), this.getId());
|
||||
this.topics.add(topicPost);
|
||||
if (topicSize() > MAX_JOINED_TOPICS_NUM) {
|
||||
throw new BusinessException(ExceptionCodeConstant.ONE_POST_MOST_JOIN_INTO_FIVE_TOPICS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int topicSize(){
|
||||
return this.topics.size();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package cn.allms.community.domain.model.post;
|
||||
|
||||
import cn.allms.community.infrastructure.constant.ExceptionCodeConstant;
|
||||
import cn.allms.community.infrastructure.exception.BusinessException;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 帖子作者对象
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 11:51
|
||||
*/
|
||||
@Data
|
||||
public class PostAuthor {
|
||||
/**
|
||||
* 帖子内容最小长度
|
||||
*/
|
||||
private final static int MIN_LENGTH_POST_SOURCE_CONTENT = 16;
|
||||
|
||||
/**
|
||||
* 作者ID
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* 作者账号
|
||||
*/
|
||||
private String account;
|
||||
/**
|
||||
* 作者昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 发布帖子
|
||||
*
|
||||
* @param title 帖子标题
|
||||
* @param sourceContent 帖子内容
|
||||
* @return
|
||||
*/
|
||||
public Post posting(String title, String sourceContent) throws BusinessException {
|
||||
long currentTimeMillis = System.currentTimeMillis();
|
||||
if (sourceContent.length() < MIN_LENGTH_POST_SOURCE_CONTENT) {
|
||||
throw new BusinessException(ExceptionCodeConstant.POST_SOURCE_CONTENT_AT_LEAST_SIXTEEN_WORDS);
|
||||
}
|
||||
Post post = new Post();
|
||||
post.setAuthorId(this.id);
|
||||
post.setSourceContent(sourceContent);
|
||||
post.setTitle(title);
|
||||
post.setPostingTime(currentTimeMillis);
|
||||
post.setLastModifyTime(currentTimeMillis);
|
||||
return post;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package cn.allms.community.domain.model.topic;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 话题对象
|
||||
*
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 14:31
|
||||
*/
|
||||
@Data
|
||||
public class Topic {
|
||||
/**
|
||||
* 话题id
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* 话题标题
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 话题描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 话题创建时间
|
||||
*/
|
||||
private Timestamp createTime;
|
||||
/**
|
||||
* 话题下的帖子列表
|
||||
*/
|
||||
private Set<TopicPost> posts;
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package cn.allms.community.domain.model.topic;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 话题文章对象
|
||||
*
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 14:31
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class TopicPost {
|
||||
private Long topicId;
|
||||
private Long postId;
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package cn.allms.community.domain.service.contentfilter;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 内容过滤器
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 15:09
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public abstract class ContentFilter {
|
||||
/**
|
||||
* 下一个内容过滤器
|
||||
*/
|
||||
private ContentFilter nextContentFilter;
|
||||
|
||||
/**
|
||||
* 过滤内容
|
||||
* @param object 过滤对象
|
||||
* @return
|
||||
*/
|
||||
public abstract boolean filterContent(Object object);
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package cn.allms.community.domain.service.contentfilter;
|
||||
|
||||
/**
|
||||
* 图片过滤器
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 15:17
|
||||
*/
|
||||
public class ImageContentFilter extends ContentFilter{
|
||||
@Override
|
||||
public boolean filterContent(Object object) {
|
||||
// TODO 调用第三方接口实现图片过滤
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package cn.allms.community.domain.service.contentfilter;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 本地文本内容过滤器
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 15:24
|
||||
*/
|
||||
public class LocalTextContentFilter extends TextContentFilter {
|
||||
/**
|
||||
* 本地敏感词
|
||||
*/
|
||||
private Set<String> sensitiveWords = new HashSet<>();
|
||||
|
||||
public LocalTextContentFilter() {
|
||||
sensitiveWords.add("NND");
|
||||
sensitiveWords.add("奶奶个熊");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean filterContent(Object content) {
|
||||
Assert.isTrue(content instanceof String, "本地文本过滤对象必须为 String 类型");
|
||||
for (String sensitiveWord : sensitiveWords) {
|
||||
if (((String) content).contains(sensitiveWord)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package cn.allms.community.domain.service.contentfilter;
|
||||
|
||||
import cn.allms.community.domain.model.post.Post;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 帖子内容过滤:包含文本过滤,图片过滤
|
||||
* 责任链模式
|
||||
*
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 15:33
|
||||
*/
|
||||
public class PostMainBodyContentFilterChain {
|
||||
/**
|
||||
* 内容过滤器
|
||||
*/
|
||||
private Set<ContentFilter> contentFilters;
|
||||
|
||||
public PostMainBodyContentFilterChain() {
|
||||
TextContentFilter localTextContentFilter = new LocalTextContentFilter();
|
||||
TextContentFilter remoteTextContentFilter = new RemoteTextContentFilter();
|
||||
ImageContentFilter imageContentFilter = new ImageContentFilter();
|
||||
// 优先校验本地的敏感词
|
||||
contentFilters.add(localTextContentFilter);
|
||||
// 第三方文本敏感词过滤
|
||||
contentFilters.add(remoteTextContentFilter);
|
||||
// 第三方图片过滤
|
||||
contentFilters.add(imageContentFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤标题
|
||||
*
|
||||
* @param post 帖子信息
|
||||
* @return true —— 通过, false —— 未通过
|
||||
*/
|
||||
public boolean filterMainBody(Post post) {
|
||||
for (ContentFilter contentFilter : contentFilters) {
|
||||
if (!contentFilter.filterContent(post.getSourceContent())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package cn.allms.community.domain.service.contentfilter;
|
||||
|
||||
import cn.allms.community.domain.model.post.Post;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 帖子标题过滤:文本过滤
|
||||
* 责任链模式
|
||||
*
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 15:40
|
||||
*/
|
||||
public class PostTitleContentFilterChain {
|
||||
/**
|
||||
* 内容过滤器
|
||||
*/
|
||||
private Set<ContentFilter> contentFilters;
|
||||
|
||||
public PostTitleContentFilterChain() {
|
||||
LocalTextContentFilter localTextContentFilter = new LocalTextContentFilter();
|
||||
RemoteTextContentFilter remoteTextContentFilter = new RemoteTextContentFilter();
|
||||
// 本地文本敏感词校验
|
||||
contentFilters.add(localTextContentFilter);
|
||||
// 第三方文本敏感词校验
|
||||
contentFilters.add(remoteTextContentFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤标题
|
||||
*
|
||||
* @param post 帖子信息
|
||||
* @return true —— 通过,false —— 未通过
|
||||
*/
|
||||
public boolean filterTitle(Post post) {
|
||||
for (ContentFilter contentFilter : contentFilters) {
|
||||
if (!contentFilter.filterContent(post.getTitle())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package cn.allms.community.domain.service.contentfilter;
|
||||
|
||||
/**
|
||||
* 远程文本内容过滤器
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 15:22
|
||||
*/
|
||||
public class RemoteTextContentFilter extends TextContentFilter{
|
||||
@Override
|
||||
public boolean filterContent(Object object) {
|
||||
// TODO 需要调用第三方服务才能实现
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package cn.allms.community.domain.service.contentfilter;
|
||||
|
||||
/**
|
||||
* 文本过滤器
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 15:18
|
||||
*/
|
||||
public abstract class TextContentFilter extends ContentFilter{
|
||||
/**
|
||||
* 文本过滤器,抽象
|
||||
* @param object 过滤对象
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public abstract boolean filterContent(Object object);
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package cn.allms.community.infrastructure.constant;
|
||||
|
||||
/**
|
||||
* 公共常量
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 14:56
|
||||
*/
|
||||
public interface CommonConstants {
|
||||
String TOPIC_SPLIT_COMMA = ",";
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package cn.allms.community.infrastructure.constant;
|
||||
|
||||
/**
|
||||
* 异常码状态常量
|
||||
*
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 14:17
|
||||
*/
|
||||
public interface ExceptionCodeConstant {
|
||||
String POST_SOURCE_CONTENT_AT_LEAST_SIXTEEN_WORDS = "2001";
|
||||
String ONE_POST_MOST_JOIN_INTO_FIVE_TOPICS = "2002";
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
package cn.allms.community.infrastructure.exception;
|
||||
|
||||
/**
|
||||
* @author xieYj
|
||||
* @date 2021/5/11 13:59
|
||||
*/
|
||||
public class BusinessException extends Exception {
|
||||
/**
|
||||
* 业务异常码
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 业务异常参数
|
||||
*/
|
||||
private Object[] arguments;
|
||||
|
||||
public BusinessException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public BusinessException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public BusinessException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public BusinessException(String code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public BusinessException(String message, Object[] arguments) {
|
||||
super(message);
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
public BusinessException(String code, String message, Object[] arguments) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
public BusinessException(String message, Object[] arguments, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
public BusinessException(String code, String message, Object[] arguments, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.code = code;
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
public BusinessException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
|
||||
public BusinessException(String code, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
|
||||
public BusinessException(String message,
|
||||
Throwable cause,
|
||||
boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
|
||||
public BusinessException(String code,
|
||||
String message,
|
||||
Throwable cause,
|
||||
boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user