// GateWay
@Component
public class AuthorizeFilter implements Ordered, GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
...
String token = request.getHeaders().getFirst("token");
...
try {
Claims claimsBody = AppJwtUtil.getClaimsBody(token);
...
// 获取用户信息
String userId = claimsBody.get("id").toString();
// 存储在header中
ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders -> {
httpHeaders.add("userId", userId);
}).build();
// 重置请求
exchange.mutate().request(serverHttpRequest);
} catch (Exception e) {
e.printStackTrace();
}
...
}
...
}
// ThreadLocal
public class WmThreadLocalUtil {
private final static ThreadLocal<WmUser> WM_USER_THREAD_LOCAL = new ThreadLocal<>();
// 存入线程中
public static void setUser(WmUser wmUser)
{
WM_USER_THREAD_LOCAL.set(wmUser);
}
// 从线程中获取
public static WmUser getUser()
{
return WM_USER_THREAD_LOCAL.get();
}
// 清理
public static void clear()
{
WM_USER_THREAD_LOCAL.remove();
}
}
// Interceptor
public class WmTokenInterceptor implements HandlerInterceptor {
/**
* 得到header中的用户信息, 并且存入到当前线程中
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String userId = request.getHeader("userId");
if(userId != null){
// 存入当前线程
WmUser wmUser = new WmUser();
wmUser.setId(Integer.valueOf(userId));
WmThreadLocalUtil.setUser(wmUser);
}
return true;
}
/**
* 清理线程中的数据
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
WmThreadLocalUtil.clear();
}
}
// WebMvcConfig
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new WmTokenInterceptor()).addPathPatterns("/**");
}
}
@Slf4j
@Service
@Transactional
public class WmMaterialServiceImpl extends ServiceImpl<WmMaterialMapper, WmMaterial> implements WmMaterialService {
@Autowired
private FileStorageService fileStorageService;
/**
* 图片上传
* @param multipartFile
* @return
*/
@Override
public ResponseResult uploadPicture(MultipartFile multipartFile) {
// 1. 检查参数
if(multipartFile == null || multipartFile.getSize() == 0){
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
// 2. 上传图片到minio中
String fileName = UUID.randomUUID().toString().replace("-", "");
String originalFilename = multipartFile.getOriginalFilename();
String postfix = originalFilename.substring(originalFilename.lastIndexOf("."));
String fileId = null;
try {
fileId = fileStorageService.uploadImgFile("", fileName+postfix, multipartFile.getInputStream());
log.info("上传图片到minio中, fileId: {}", fileId);
} catch (IOException e) {
log.error("WmMaterialServiceImpl-上传文件失败");
throw new RuntimeException(e);
}
// 3. 保存到数据库中
WmMaterial wmMaterial = new WmMaterial();
wmMaterial.setUserId(WmThreadLocalUtil.getUser().getId());
wmMaterial.setUrl(fileId);
wmMaterial.setIsCollection((short) 0);
wmMaterial.setType((short) 0);
wmMaterial.setCreatedTime(new Date());
save(wmMaterial);
// 4. 返回结果
return ResponseResult.okResult(wmMaterial);
}
}
// WmMaterialDto
@Data
public class WmMaterialDto extends PageRequestDto {
/**
* 1.收藏, 0.未收藏
*/
private Short isCollection;
}
// Service
@Override
public ResponseResult findList(WmMaterialDto dto) {
// 1. 检查参数
dto.checkParam();
// 2. 分页查询
IPage page = new Page(dto.getPage(), dto.getSize());
LambdaQueryWrapper<WmMaterial> queryWrapper = new LambdaQueryWrapper<>();
// 是否收藏
if(dto.getIsCollection() != null && dto.getIsCollection() == 1){
queryWrapper.eq(WmMaterial::getIsCollection, 1);
}
// 按照用户查询
queryWrapper.eq(WmMaterial::getUserId, WmThreadLocalUtil.getUser().getId());
// 按照时间倒序排序
queryWrapper.orderByDesc(WmMaterial::getCreatedTime);
page(page, queryWrapper);
PageResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
result.setData(page.getRecords());
// 3. 结果返回
return result;
}
@Override
public ResponseResult findAll() {
return ResponseResult.okResult(list());
}
// WmNewsPageReqDto
@Data
public class WmNewsPageReqDto extends PageRequestDto {
/**
* 状态
*/
private Short status;
/**
* 开始时间
*/
private Date beginPubDate;
/**
* 结束时间
*/
private Date endPubDate;
/**
* 所属频道ID
*/
private Integer channelId;
/**
* 关键字
*/
private String keyword;
}
// Service
@Service
@Slf4j
@Transactional
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
/**
* 查询文章
* @param dto
* @return
*/
@Override
public ResponseResult findAll(WmNewsPageReqDto dto) {
// 1. 参数检验
dto.checkParam();
// 2. 分页查询
IPage page = new Page(dto.getPage(), dto.getSize());
LambdaQueryWrapper<WmNews> queryWrapper = new LambdaQueryWrapper<>();
// 2.1 查询状态
queryWrapper.eq(dto.getStatus()!=null, WmNews::getStatus, dto.getStatus());
// 2.2 查询所属频道
queryWrapper.eq(dto.getChannelId()!=null, WmNews::getChannelId, dto.getChannelId());
// 2.3 查询关键字
queryWrapper.like(dto.getKeyword()!=null, WmNews::getTitle, dto.getKeyword());
// 2.4 查询时间
queryWrapper.between(dto.getBeginPubDate()!=null&&dto.getEndPubDate()!=null, WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate());
// 2.5 根据当前用户查询
queryWrapper.eq(WmNews::getUserId, WmThreadLocalUtil.getUser().getId());
// 2.6 根据发布时间倒序排序
queryWrapper.orderByDesc(WmNews::getPublishTime);
// 2.7 查询结果
page(page, queryWrapper);
// 3. 返回结果
PageResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
result.setData(page.getRecords());
return result;
}
}
// WmNewsDto
public class WmNewsDto {
private Integer id;
/**
* 标题
*/
private String title;
/**
* 频道id
*/
private Integer channelId;
/**
* 标签
*/
private String labels;
/**
* 发布时间
*/
private Date publishTime;
/**
* 文章内容
*/
private String content;
/**
* 文章封面类型 0 无图 1 单图 3 多图 -1 自动
*/
private Short type;
/**
* 提交时间
*/
private Date submitedTime;
/**
* 状态 提交为1 草稿为0
*/
private Short status;
/**
* 封面图片列表 多张图以逗号隔开
*/
private List<String> images;
}
// Service
@Service
@Slf4j
@Transactional
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
/**
* 发布文章或保存草稿
* @param dto
* @return
*/
@Override
public ResponseResult submitNews(WmNewsDto dto) {
// 1. 检查数据
if(dto == null || dto.getContent() == null){
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
// 2. 保存或修改文章
WmNews wmNews = new WmNews();
// 属性拷贝, 属性名和类型相同才能拷贝
BeanUtils.copyProperties(dto, wmNews);
// 封面图片: List -> String
if(dto.getImages() != null && dto.getImages().size() > 0){
String imagesStr = StringUtils.join(dto.getImages(), ",");
wmNews.setImages(imagesStr);
}
// 如果当前封面类型为自动-1
if(dto.getType() == WemediaConstants.WM_NEWS_TYPE_AUTO){
wmNews.setType(null);
}
saveOrUpdateWmNews(wmNews);
// 3. 判断是否为草稿, 如果为草稿结束当前方法
if(dto.getStatus() == WmNews.Status.NORMAL.getCode()){
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
// 获取到文章内容中的图片信息
List<String> materials = extractUrlInfo(dto.getContent());
// 4. 不是草稿, 保存文章内容图片与素材的关系
saveRelativeInfoForContent(materials, wmNews.getId());
// 5. 不是草稿, 保存文章封面图片与素材的关系
saveRelativeInfoForCover(dto, wmNews, materials);
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
/**
* 1. 若封面类型为自动, 则需设置封面类型的数据
* 2. 保存封面图片与素材的关系
*/
private void saveRelativeInfoForCover(WmNewsDto dto, WmNews wmNews, List<String> materials) {
// 自动类型设置封面类型的数据
List<String> imgsCover = dto.getImages();
if(dto.getType() == WemediaConstants.WM_NEWS_TYPE_AUTO){
if(materials.size() >= 3){
wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
imgsCover = materials.stream().limit(3).collect(Collectors.toList());
}else if(materials.size() >= 1){
wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
imgsCover = materials.stream().limit(1).collect(Collectors.toList());
}else{
wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
}
// 修改文章
if(imgsCover!=null && imgsCover.size() > 0){
wmNews.setImages(StringUtils.join(imgsCover, ","));
}
updateById(wmNews);
}
// 保存封面图片与素材的关系
if(imgsCover!=null && imgsCover.size() > 0){
saveRelativeInfo(imgsCover, wmNews.getId(), WemediaConstants.WM_COVER_REFERENCE);
}
}
/**
* 处理文章内容图片与素材的关系
* @param materials
* @param newsId
*/
private void saveRelativeInfoForContent(List<String> materials, Integer newsId) {
saveRelativeInfo(materials, newsId, WemediaConstants.WM_CONTENT_REFERENCE);
}
@Autowired
private WmMaterialMapper wmMaterialMapper;
/**
* 保存文章图片与素材的关系到数据库中
* @param materials
* @param newsId
* @param type
*/
private void saveRelativeInfo(List<String> materials, Integer newsId, Short type) {
if(materials==null || materials.isEmpty()){
return;
}
// 通过url查询id
LambdaQueryWrapper<WmMaterial> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(WmMaterial::getUrl, materials);
List<WmMaterial> wmMaterialList = wmMaterialMapper.selectList(queryWrapper);
// 判断素材是否有效
if(wmMaterialList==null || wmMaterialList.size()!=materials.size()){
// 手动抛出异常
// 1. 提示调用者素材失效
// 2. 进行数据的回滚
throw new CustomException(AppHttpCodeEnum.MATERIAL_REFERENCE_FAIL);
}
List<Integer> ids = wmMaterialList.stream().map(WmMaterial::getId).collect(Collectors.toList());
wmNewsMaterialMapper.saveRelations(ids, newsId, type);
}
private List<String> extractUrlInfo(String content) {
List<String> materials = new ArrayList<>();
List<Map> maps = JSON.parseArray(content, Map.class);
for (Map map : maps) {
if(map.get("type").equals("image")){
String imgUrl = (String) map.get("value");
materials.add(imgUrl);
}
}
return materials;
}
@Autowired
private WmNewsMaterialMapper wmNewsMaterialMapper;
/**
* 保存或修改文章
* @param wmNews
*/
private void saveOrUpdateWmNews(WmNews wmNews) {
// 补全属性
wmNews.setUserId(WmThreadLocalUtil.getUser().getId());
wmNews.setCreatedTime(new Date());
wmNews.setSubmitedTime(new Date());
wmNews.setEnable((short) 1); // 默认上架
if(wmNews.getId() == null){
// 保存
save(wmNews);
}else{
// 修改
// 删除文章图片和素材的关系
LambdaQueryWrapper<WmNewsMaterial> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(WmNewsMaterial::getNewsId, wmNews.getId());
wmNewsMaterialMapper.delete(queryWrapper);
updateById(wmNews);
}
}
}
黑马程序员. 黑马头条