JavaWeb_LeadNews_Day3-图片管理, 文章管理
- 图片管理
- 图片上传
- 实现思路
- 获取用户信息
- 将图片上传至minio
- 图片列表
- 文章管理
- 频道列表查询
- 文章列表查询
- 文章发布
- 实现思路
- 具体代码
- 来源
图片管理
图片上传
实现思路
- 在GateWay解析前端请求, 获取用户信息, 存储在header中
- 在Interceptor得到header中的用户信息, 存入当前线程
- 将图片上传到minio中, 得到图片路径
- 将用户id, 图片路径及其他数据保存到素材表中
获取用户信息
// GateWay
@Component
public class AuthorizeFilter implements Ordered, GlobalFilter {@Overridepublic 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中的用户信息, 并且存入到当前线程中*/@Overridepublic 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;}/*** 清理线程中的数据*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {WmThreadLocalUtil.clear();}
}// WebMvcConfig
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new WmTokenInterceptor()).addPathPatterns("/**");}
}
将图片上传至minio
@Slf4j
@Service
@Transactional
public class WmMaterialServiceImpl extends ServiceImpl<WmMaterialMapper, WmMaterial> implements WmMaterialService {@Autowiredprivate FileStorageService fileStorageService;/*** 图片上传* @param multipartFile* @return*/@Overridepublic 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*/@Overridepublic 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;}
}
文章发布
实现思路
- 文章提交审核或者存入草稿
- 存在id, 删除文章素材关系表中的关联关系, 修改文章
- 不存在id, 新增文章
- 是草稿, 草稿无需在文章素材关系表中保存关联关系
- 不是草稿, 在文章素材关系表中保存内容图片
- 不是草稿, 在文章素材关系表中保存封面图片
具体代码
// 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*/@Overridepublic 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 -> Stringif(dto.getImages() != null && dto.getImages().size() > 0){String imagesStr = StringUtils.join(dto.getImages(), ",");wmNews.setImages(imagesStr);}// 如果当前封面类型为自动-1if(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);}@Autowiredprivate 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查询idLambdaQueryWrapper<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;}@Autowiredprivate 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);}}
}
来源
黑马程序员. 黑马头条