需求:后端需要提供一个文章发布的接口,接口中需要先对文章内容进行如下校验,校验通过后才能发布
1. 文章长度不能超过1万个字符
2. 不能有敏感词
3. 文章中图片需要合规
责任链相当于一个链条一样,链条上有很多节点,节点与节点之间形成了一个单向的链表。
每个节点相当于一个处理步骤,一个任务过来后,会交给链条上第一个节点进行处理,第一个节点处理后再传递给下一个节点,下一个节点处理完成后,继续向后传递。
目前文章发布中的校验有下面3个步骤,每个步骤相当于责任链上一个节点,每个步骤对应一个类,如果要进行扩展,只需要添加一个类,然后调整下链表的顺序便可。
具体实现
1 pom.xml
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
2 pojo类,ArticlePublishRequest: 数据传输对象,封装了文章发布请求的数据。
import lombok.Data;
@Data
public class ArticlePublishRequest {
// 文章内容
private String content;
}
3 IArticlePublishCheck: 定义文章发布校验的接口,包含校验和设置下一个校验器的方法
import com.example.demo_23.aaaaa.dto.ArticlePublishRequest;
public interface IArticlePublishCheck {
/**
* 对文章进行校验
*
* @param req
*/
void check(ArticlePublishRequest req);
/**
* 设置下一个文章校验器,并返回下一个校验器
*
* @param next
* @return
*/
IArticlePublishCheck setNext(IArticlePublishCheck next);
}
4 AbstractCheck: 提供责任链模式的抽象实现,包含默认的校验流程和设置下一个校验器的逻辑
import com.example.demo_23.aaaaa.dto.ArticlePublishRequest;
public abstract class AbstractCheck implements IArticlePublishCheck {
private IArticlePublishCheck next;
@Override
public void check(ArticlePublishRequest req) {
//校验
this.checkIn(req);
//调用下一个校验器进行校验
if (this.next != null) {
this.next.check(req);
}
}
/**
* 子类实现
*
* @param req
*/
protected abstract void checkIn(ArticlePublishRequest req);
@Override
public IArticlePublishCheck setNext(IArticlePublishCheck next) {
this.next = next;
return this.next;
}
}
5 校验具体实现类
-
ContentLengthCheck: 实现内容长度校验,确保文章内容长度在合理范围内。
-
ImageCheck: 实现图片合法性校验,确保文章中的图片是合法的(当前未实现具体逻辑)。
-
PublishCountCheck: 实现发布次数校验,限制用户每天发布文章的数量。
-
SensitiveWordsCheck: 实现敏感词校验,确保文章内容不包含敏感词汇。
import com.example.demo_23.aaaaa.dto.ArticlePublishRequest;
import org.apache.commons.lang3.StringUtils;
/**
* 内容长度校验
*/
public class ContentLengthCheck extends AbstractCheck {
@Override
protected void checkIn(ArticlePublishRequest req) {
if (StringUtils.length(req.getContent()) < 1 || StringUtils.length(req.getContent()) > 10) {
throw new RuntimeException("文章长度不能超过10000个字符");
}
}
}
---------------------------------------------
import com.example.demo_23.aaaaa.dto.ArticlePublishRequest;
/**
* 图片合法性校验
*/
public class ImageCheck extends AbstractCheck {
@Override
protected void checkIn(ArticlePublishRequest req) {
//校验图片是否合法?不合法则抛出异常
boolean checked = true;
if (!checked) {
throw new RuntimeException("图片不合法");
}
}
}
---------------------------------------------
import com.example.demo_23.aaaaa.dto.ArticlePublishRequest;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 发布次数校验器,每日限制5篇文章
*/
public class PublishCountCheck extends AbstractCheck {
AtomicInteger publishCount = new AtomicInteger(0);
@Override
protected void checkIn(ArticlePublishRequest req) {
if (publishCount.incrementAndGet() > 5) {
//发布次数校验,比如每日只允许发布5篇文章
throw new RuntimeException("今日发布已满,请明日继续分享!");
}
}
}
---------------------------------------------
import com.example.demo_23.aaaaa.dto.ArticlePublishRequest;
import java.util.Arrays;
import java.util.List;
/**
* 敏感词校验
*/
public class SensitiveWordsCheck extends AbstractCheck {
@Override
protected void checkIn(ArticlePublishRequest req) {
//敏感词列表
List<String> sensitiveWordsList = Arrays.asList("逼");
//有敏感词则抛出异常
for (String sw : sensitiveWordsList) {
if (req.getContent().contains(sw)) {
throw new RuntimeException("有敏感词:" + sw);
}
}
}
}
6 ArticleCheckConfig: 配置类,负责创建和配置责任链中各个校验器,并设置它们之间的顺序。
import com.example.demo_23.aaaaa.article.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ArticleCheckConfig {
@Bean
public ContentLengthCheck contentLengthCheck() {
return new ContentLengthCheck();
}
@Bean
public SensitiveWordsCheck sensitiveWordsCheck() {
return new SensitiveWordsCheck();
}
@Bean
public ImageCheck imageCheck() {
return new ImageCheck();
}
@Bean
public PublishCountCheck publishCountCheck() {
return new PublishCountCheck();
}
@Bean
public IArticlePublishCheck articlePublishCheck() {
ContentLengthCheck firstCheck = this.contentLengthCheck();
firstCheck
.setNext(this.sensitiveWordsCheck())
.setNext(this.imageCheck())
.setNext(this.publishCountCheck())
;
return firstCheck;
}
}
7 ArticleController: 控制器类,处理文章发布请求,使用责任链进行校验。
import com.example.demo_23.aaaaa.article.IArticlePublishCheck;
import com.example.demo_23.aaaaa.dto.ArticlePublishRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ArticleController {
@Autowired
private IArticlePublishCheck articlePublishCheck;
/**
* 发布文章,责任链版本实现,更容易扩展
*
* @param req
* @return
*/
@PostMapping("/article/publishNew")
public Object publishNew(@RequestBody ArticlePublishRequest req) {
try {
this.articlePublishCheck.check(req);
return "发布成功";
} catch (RuntimeException e) {
return "发布失败:" + e.getMessage();
}
}
}