JavaWeb_LeadNews_Day3-图片管理, 文章管理

JavaWeb_LeadNews_Day3-图片管理, 文章管理

  • 图片管理
    • 图片上传
      • 实现思路
      • 获取用户信息
      • 将图片上传至minio
    • 图片列表
  • 文章管理
    • 频道列表查询
    • 文章列表查询
    • 文章发布
      • 实现思路
      • 具体代码
  • 来源

图片管理

图片上传

实现思路

  1. 在GateWay解析前端请求, 获取用户信息, 存储在header中
  2. 在Interceptor得到header中的用户信息, 存入当前线程
  3. 将图片上传到minio中, 得到图片路径
  4. 将用户id, 图片路径及其他数据保存到素材表中

获取用户信息

// 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("/**");
    }
}

将图片上传至minio

@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;
    }
}

文章发布

实现思路

  1. 文章提交审核或者存入草稿
  2. 存在id, 删除文章素材关系表中的关联关系, 修改文章
  3. 不存在id, 新增文章
  4. 是草稿, 草稿无需在文章素材关系表中保存关联关系
  5. 不是草稿, 在文章素材关系表中保存内容图片
  6. 不是草稿, 在文章素材关系表中保存封面图片

具体代码

// 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);
        }
    }
}

来源

黑马程序员. 黑马头条

你可能感兴趣的:(JavaWeb开发,#,后端,spring,boot,spring,cloud,minio,微服务,java,spring)