图片上传

c18735c1b19a4b0591b3f57e9f16d92d.png

  1. 前端发请求后到达网关,网关会解析用户token后可以得到用户信息,把用户信息放入请求头中继续向自媒体微服务发请求,在自媒体用户微服务的拦截器中就可以获得用户信息。
  2. 在自媒体微服务会把图片存储到minio中,并在数据库中存储图片的路径
  1. 网关传递userId给自媒体微服务:
@Component
@Slf4j
public class AuthorizeFilter implements Ordered, GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1.获取request和response对象
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//2.判断是否是登录
if(request.getURI().getPath().contains("/login")){
//放行
return chain.filter(exchange);
}
//3.获取token
String token = request.getHeaders().getFirst("token");
//4.判断token是否存在
if(StringUtils.isBlank(token)){
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
//5.判断token是否有效
try {
Claims claimsBody = AppJwtUtil.getClaimsBody(token);
//是否是过期
int result = AppJwtUtil.verifyToken(claimsBody);
if(result == 1 || result == 2){
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// token没问题
Object userId = claimsBody.get("id");
// 把token放入请求头中传给自媒体微服务
ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders -> {
httpHeaders.add("userId", userId + "");
}).build();
exchange.mutate().request(serverHttpRequest);// 重置请求
} catch (Exception e) {
e.printStackTrace();
}
//6.放行
return chain.filter(exchange);
}
/**
* 优先级设置 值越小 优先级越高
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
  1. 自媒体微服务的拦截器拦截到userId后存入ThreadLocal中
public class LoginInterceptor implements HandlerInterceptor {
// 前置方法(得到header中的用户信息并存入当前线程中)
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1.从请求头中获取用户信息
String userId = request.getHeader("userId");
// 2.存入ThreadLocal中
if(StringUtils.isNotBlank(userId)) {
WmUser wmUser = new WmUser();
wmUser.setApUserId(Integer.parseInt(userId));
WmThreadLocalUtil.setUser(wmUser);
}
// 3. 放行
return true;
}

// 后置方法(清理线程中的数据)
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 清理用户
WmThreadLocalUtil.clear();
}
}

配置使自定义拦截器生效

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**");
}
}

文章自动审核流程

  1. 文章发布后,系统自动审核,主要是通过第三方接口对文章内容进行审核(成功、失败、不确定)。
  2. 自动审核返回不确定信息时,转到人工审核,由平台管理员进行审核。
    0f81e5cbf552466d9118ee05280ed9f9.png

先审核文章,再审核图片,如果文章和图片都通过了,修改文章状态;如果有一个没有审核通过,转为人工审核。
其中审核时调用阿里云的第三方接口

内容安全第三方接口

内容安全是识别服务,支持对图片、视频、文本、语音等对象进行多样化场景检测,有效降低内容违规风险。
阿里云内容安全文档
文本审核

分布式id

随着业务的增长,文章表可能会占用很大的物理存储空间,为了解决该问题,后期使用数据库分片技术,将一个数据库进行拆分,通过数据库中间件连接。如果数据库中该表选用id自增策略,则可能产生重复的id,就可以使用分布式id生成策略。
8f7f0ab1a45d494e860b31e4063d1f06.png

分布式id生成策略

f361435dea7442ad9e5c47386fa59e89.png
雪花算法:
3ba06efd4b1542258f7fa83629b42522.png

  1. 在实体类中的id上加入以下配置:
@TableId(value = "id",type = IdType.ID_WORKER)
private Long id;
  1. 在配置文件中配置数据中心id和机器id
mybatis-plus:
mapper-locations: classpath*:mapper/*.xml
# 设置别名包扫描路径,通过该属性可以给包中的类注册别名
type-aliases-package: com.heima.model.article.pojos
global-config:
datacenter-id: 1 # 数据中心id(范围:0-31)
workerId: 1 # 机器id(范围:0-31)

Feign远程调用服务降级处理

  1. 编写降级逻辑
 @Component
public class IArticleClientFallback implements IArticleClient {
@Override
public ResponseResult saveArticle(ArticleDto articleDto) {
return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "获取数据失败");
}
}
  1. 远程接口中指向降级代码
@FeignClient(value = "leadnews-article", fallback = IArticleClientFallback.class) // 指向降级代码
public interface IArticleClient {
@PostMapping("/api/v1/article/save")
public ResponseResult saveArticle(@RequestBody ArticleDto articleDto);
}
  1. 客户端开启对熔断降级的支持
feign:
# 开启feign对hystrix熔断降级的支持
hystrix:
enabled: true
# 修改调用超时时间
client:
config:
default:
connectTimeout: 2000
readTimeout: 2000

同步调用和异步调用

4beb87b53ac54e50ad3a05e2e56aaa3c.png

同步:发出一个调用后,没有得到结果之前,该调用不返回(实时处理)
异步:调用在发出后,这个调用直接返回了,没有返回结果(分时处理)

SpringBoot集成异步线程调用

  1. 在自动审核的方法上加@Async注解(标明要异步调用)
  2. 在文章发布成功后异步调用审核的方法
  3. 在自媒体引导类中使用@EnableAsync注解开启异步调用

自管理敏感词过滤

自管理敏感词过滤(文本)

2c687d18fe064afc8f865d09571c18c3.png

DFA确定有穷自动机

一次性把所有的敏感词存储到多个map中。
cf31722e5c574004840a064118418373.png

实现原理:

d573133dd34c41eaaa3076649c8e3a46.png

自管理敏感词过滤(图片)

图片文字识别OCR

82684bcc593349d4b8593b5508162b64.png
Tess4J支持多种输出格式:纯文本、hOCR(HTML)、PDF等

  1. 导入依赖:
<dependency>
<groupId>net.sourceforge.tess4j</groupId>
<artifactId>tess4j</artifactId>
<version>4.1.1</version>
</dependency>
  1. 导入中文字体库
  2. 识别图片中的文字
public static void main( String[] args ) throws TesseractException {
// 创建实例
ITesseract tesseract = new Tesseract();
// 设置字体库路径
tesseract.setDatapath("D:\\project\\kaiFa\\heiMaProject\\weiFuWu\\leadnews");
// 设置语言
tesseract.setLanguage("chi_sim");
// 识别图片
File file = new File("D:\\project\\kaiFa\\heiMaProject\\weiFuWu\\leadnews\\image-20210524161243572.png");
String res = tesseract.doOCR(file);
System.out.println(res.replaceAll("\\r|\\n", "-"));
}