@Component
public class TokenInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(TokenInterceptor.class);
@Autowired
private RedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 1.判断当前请求方法上是否存在RequiredToken注解
boolean requiredToken = ((HandlerMethod) handler).getMethod().isAnnotationPresent(RequiredToken.class);
// 2.若存在该注解
if (requiredToken) {
// 1. 获取token信息
String token = request.getParameter("token");
log.info("当前传递的token为:{}", token);
// 2. 拼接前缀
String tokenKey = RedisPrefix.TOKEN_KEY + token;
// 3. 根据tokenKey获取用户信息
User o = (User) redisTemplate.opsForValue().get(tokenKey);
if (o == null) throw new RuntimeException("提示: 令牌无效,无效token!");
// 4. 存储到当前请求的上下文中
request.setAttribute("token", token);
request.setAttribute("user", o);
}
return true;
}
}
step2: 配置拦截器(easywatch_users->…->config->MvcConfig)
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Autowired
private TokenInterceptor tokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/**"); // 拦截所有
}
}
step3: 自定义注解(easywatch_users->…->annotations->RequiredToken)
@Retention(RetentionPolicy.RUNTIME) // 运行时有效
@Target(ElementType.METHOD) // 加载方法上
public @interface RequiredToken {
}
step4: controller中的使用一例(easywatch_users->…->controller->UserContrller)
// 用户收藏列表
@GetMapping("/user/favorites")
@RequiredToken
public List<VideoVO> favorites(HttpServletRequest request) {
User user = (User) request.getAttribute("user");
List<VideoVO> videoVOS = favoriteService.findFavoritesByUserId(user.getId());
log.info("当前用户收藏的视频为:{}", JSONUtils.writeJSON(videoVOS));
return videoVOS;
}
<!--spring-cloud-stater-openfeign(用于完成服务间调用)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
step2:在easywatch_users入口类加入注解开启openfeign支持
@SpringBootApplication
@EnableFeignClients // 开启支持openFeign组件的调用
public class ApiUsersApplication {
public static void main(String[] args) {
SpringApplication.run(ApiUsersApplication.class, args);
}
}
step3:新建feignclients->VideoClient接口
package com.salieri.feignclients;
...
// 调用API-VIDEOS服务的openfeign组件
@FeignClient("API-VIDEOS") // 用来标识当前接口是一个 feign 的组件
public interface VideosClient {
@PostMapping("publish")
Video publish(@RequestBody Video video); //RequestBody将json格式数据转为对象信息
@GetMapping("getVideos")
List<VideoVO> getVideos(@RequestParam("ids") List<Integer> ids);
}
step4: UserController中注入VideoClient并使用
@Autowired
private VideosClient videosClient;
@PostMapping("/user/videos")
@RequiredToken
public Video publishVideos(MultipartFile file, Video video, Integer category_id, HttpServletRequest request) throws IOException {
...
// 调用视频服务
Video videoResult = videosClient.publish(video);
log.info("视频发布成功之后返回的视频信息: {}", JSONUtils.writeJSON(videoResult));
return videoResult;
}
<!-- 引入mq -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
step2: 在easywatch-videos的配置文件中写入rabbitmq相关的配置
...
rabbitmq:
host: 10.15.0.2
port: 5672
username: guest
password: guest
virtual-host: /
step3: rabbitmq生产者生产消息–>在VideoServiceImpl中
@Autowired
private RabbitTemplate rabbitTemplate;
===========
@Override
public Video insert(Video video) {
video.setCreatedAt(new Date());//设置创建日期
video.setUpdatedAt(new Date());//设置更新日期
this.videoDao.insert(video);
// 利用MQ异步处理来提升系统响应。
// 将视频信息写入到ES索引库
rabbitTemplate.convertAndSend("videos", "", JSONUtils.writeJSON(getVideoVO(video)));
return video;
}
step4: rabbitmq消费者消费消息–>在easywatch_search微服务中引入rabbitmq依赖,写rabbitmq配置,而后在 easywatch_search->…->mq->VideoConsumer中进行如下配置
package com.salieri.mq;
@Component
public class VideoConsumer {
private static final Logger log = LoggerFactory.getLogger(VideoConsumer.class);
@Autowired
private RestHighLevelClient restHighLevelClient;
@RabbitListener(bindings = @QueueBinding(
value = @Queue,
exchange = @Exchange(name = "videos", type = "fanout")
))
public void receive(String message) throws IOException {
log.info("MQ将接收video信息为:{}", message);
// 1. 将mq中video的json格式数据转为一个videoVO对象
// 这里的videoVO跟easywatch_videos中转成message的对象是同一个
VideoVO videoVO = new ObjectMapper().readValue(message, VideoVO.class);
// 2.创建ES中索引请求对象 参数1:操作索引 参数2:操作类型 参数3:文档id
IndexRequest indexRequest = new IndexRequest("video", "video", videoVO.getId().toString());
// 3.设置ES文档的内容
indexRequest.source(message, XContentType.JSON);
// 4.执行索引操作(录入索引)
IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
log.info("video信息录入ES的状态为: {}", indexResponse.status());
}
}
PUT /video
{
"mappings": {
"video":{
"properties":{
"title":{
"type":"text",
"analyzer":"ik_max_word"
},
"cover":{
"type":"keyword"
},
"likes":{
"type":"integer"
},
"uploader":{
"type":"keyword"
},
"created_at":{
"type":"date"
}
}
}
}
}
step2: 通过sringboot录入数据
针对easywatch_search微服务,首先引入依赖;而后写config->RestClientConfig,进行springboot整合es的配置;而后写mq->VideoConsumer。
// 视频播放
@PutMapping("/user/played/{id}")
public void played(@PathVariable("id") String videoId, HttpServletRequest request) {
// 当前视频在redis中的播放次数+1
stringRedisTemplate.opsForHash().increment("PLAYED", RedisPrefix.PLAYED_KEY + videoId, 1);
// 获取登录用户信息
User user = getUser(request);
if (!ObjectUtils.isEmpty(user)) {
// 记录用户的播放历史
Played played = new Played();
played.setUid(user.getId());
played.setVideoId(Integer.valueOf(videoId));
// insert中:当用户第一次播放视频时判断为新增,当用户非第一次播放时判断为更新
played = playedService.insert(played);
log.info("当前用户的播放记录保存成功,信息为:{}", JSONUtils.writeJSON(played));
}
}