在自媒体后台中主要包含的功能有内容管理:素材管理、文章发布、内容列表的查看、评论列表查看、图文数据统计;粉丝管理:粉丝概况、粉丝画像、粉丝列表
本案例开发功能包括:
根据不同时间范围查询图文明细数据
发布文章、保存草稿
根据状态查询当前用户的内容数据、修改、删除
素材查看、收藏素材、删除素材、取消收藏
粉丝概况:性别分布、年龄分布、终端分布、七日阅读量分布
在图文数据中我们主要实现自媒体用户所发布的文章的相关数据(发布量、阅读量、点赞量、评论量、收藏量、转发量、不喜欢)统计,为自媒体用户提供直观的运营数据。
素材管理部分的相关需求主要是实现图片的上传、删除、查询等功能,提供给自媒体人图文素材管理的空间。
发布文章部分主要实现自媒体用户编辑文章内容,进行文章的发布或则保存草稿。
内容列表功能模块, 主要实现根据不同的条件对文章内容进行查询,以及对文章的删除、修改等操作。
粉丝概况和图文数据功能类似,但此处统计的数据只是当前自媒体用户的粉丝产生的相关数据。
本功能会涉及以下相关数据表,用于读取文章内容和配置,存储在文章详情页面产生的各种行为,相关表的Mycat路由定义如下:
表名 | 描述 | 主键方式 | 存放DN | 分表字段 |
---|---|---|---|---|
wm_news_statistics | 自媒体图文数据统计表 | zk_sequence | DN[0~5] | burst=(id,user_id) |
wm_sub_user | 自媒体子账号信息表 | auto_increment | DN[0~2] | parent_id |
wm_user_auth | 自媒体子账号权限信息表 | auto_increment | DN[1~3] | user_id |
wm_user | 自媒体用户信息表 | auto_increment | DN[0~5] | id |
wm_user_login | 自媒体用户登录行为信息表 | auto_increment | DN[4] | user_id |
wm_user_equipment | 自媒体用户设备信息表 | auto_increment | DN[1~3] | user_id |
wm_fans_statistics | 自媒体粉丝数据统计表 | zk_sequence | DN[0~5] | burst=(id,user_id) |
wm_fans_portrait | 自媒体粉丝画像信息表 | zk_sequence | DN[0~5] | burst=(id,user_id) |
wm_news | 自媒体图文内容信息表 | auto_increment | DN[0] | id |
wm_material | 自媒体图文素材信息表 | auto_increment | DN[0] | id |
wm_news_statistics | 自媒体图文数据统计表 | auto_increment | DN[0] | id |
自媒体服务:heima-leadnews-media
自媒体后端,主要接口如下:
登录功能
素材管理相关:
上传图片接口:用于上传用户提交的图片到素材库
删除图片接口:用于用户删除拥有的素材
收藏图片接口:收藏某个素材
取消收藏:取消收藏
素材列表:用户所有的素材
文章发布相关:
提交文章接口:用于提交文章
保存草稿接口:用于提交草稿文章
列表接口:用于查询当前用户的文章
详情接口接口:用于查询某篇文章详情
删除接口:用于删除谋篇文章
统计相关:
图文数据统计:当前自媒体用户文章被游客以及粉丝操作的相关数据
粉丝相关文章数据统计: 由粉丝对文章的相关操作产生的数据
在父工程下heima-leadnews创建模块heima-leadnews-media,从其他模块分别拷贝maven_dev.properties、
maven_prod.properties、maven_test.properties到项目的根目录
拷贝application.properties、log4j2.xml到项目的resources目录下,修改application.properties
server.port=${port.media}
spring.application.name=${sn.media}
从其他微服务下拷贝pom文件,创建对应模块的包名及引导类
分别引入mysql、jackson,security的配置
参考标准 | 请参考通用接口规范 |
---|---|
接口名称 | /login/in |
请求DTO | com.heima.model.media.pojos.WmUser |
响应DTO | 返回map{token:xxx,user:{…}} |
WmUser 用户实体com.heima.model.media.pojos.WmUser
@Data
public class WmUser {private Long id;private String name;private String password;private String salt;private String nickname;private String image;private String location;private String phone;private Integer status;private String email;private Integer type;private Integer score;private Long apUserId;private Integer apAuthorId;private Date loginTime;private Date createdTime;
}
创建mapper接口:com.heima.model.mappers.wemedia.WmUserMapper
public interface WmUserMapper {WmUser selectByName(String name);
}
WmUserMapper.xml
id, name, password, ap_user_id, ap_author_id, salt, nickname, image, location, phone, status, email, type,score, login_time, created_time
(1)创建接口com.heima.media.service.UserLoginService
public interface UserLoginService {ResponseResult login(WmUser user);
}
(2)实现类UserLoginServiceImpl
@Service
public class UserLoginServiceImpl implements UserLoginService {@Autowiredprivate WmUserMapper wmUserMapper;public ResponseResult login(WmUser user){if (StringUtils.isEmpty(user.getName())&&StringUtils.isEmpty(user.getPassword())) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE,"用户名和密码不能为空");}WmUser wmUser = wmUserMapper.selectByName(user.getName());if(wmUser!=null){if(user.getPassword().equals(wmUser.getPassword())){Map map = Maps.newHashMap();wmUser.setPassword("");wmUser.setSalt("");map.put("token",AppJwtUtil.getToken(wmUser));map.put("user",wmUser);return ResponseResult.okResult(map);}else{return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);}}else{return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"用户不存在");}}
}
(3)创建apis接口
public interface LoginControllerApi {public ResponseResult login(WmUser user);
}
(4)实现controller:com.heima.media.controller.v1.LoginController
@RestController
@RequestMapping("/login")
public class LoginController implements LoginControllerApi {@Autowiredprivate UserLoginService userLoginService ;@Override@RequestMapping("/in")public ResponseResult login(@RequestBody WmUser user){return userLoginService.login(user);}
}
在src/constants/api.js中定义常量映射到后端请求地址
export const API_USERAUTH = '/login/in' //用户认证
在src/api/login.js中定义请求方法,在请求成功之后,需要把后台返回的token数据写入本地缓存
import request from '@/utils/request'
import {setUser} from '@/utils/store'
import { API_GETPHONECODE , API_USERAUTH , API_CAPTCHAS } from '@/constants/api'export function loginByUsername(name,password) {const data = {name,password}return request({url: API_USERAUTH,method: 'post',data}).then(result => {if(result['code']==0){let temp = result.datasetUser({name:temp.user.name,photo:null,token:temp.token}) //设置用户的个人数据}return result})
}
在src/router.js中asyncRouterMap对象的children数组中增加以下改动,以满足全局自动记录路由的功能:
设置登录为起始路由
export const asyncRouterMap = [{path: "/",component: Layout,redirect:'/login', //默认子路由name:'mainIndex',children:[{path:'/index',component: () => import('@/views/dashboard/index.vue'),}]},{path: '/login',component: () => import('@/views/login/index.vue'),},{path: '*',component: () => import('@/views/404.vue'),}
]
var myRouter = new Router({routes: asyncRouterMap
})
export default myRouter
0.2.0
com.luhuiguo fastdfs-spring-boot-starter ${fastdfs.version} logback-classic ch.qos.logback
com.luhuiguo fastdfs-spring-boot-starter logback-classic ch.qos.logback
fast.dfs.connect-timeout=3000
fast.dfs.so-timeout=6000
fast.dfs.tracker-server=192.168.25.133:22122
在common下创建类:com.heima.common.fastdfs.FastDfsConfig,重载自动装载dfs和设定连接池。
/*** 自动化配置核心数据库的连接配置*/
@Setter
@Getter
@Configuration
@ConfigurationProperties(prefix="fast.dfs")
@PropertySource("classpath:fast-dfs.properties")
public class FastDfsConfig extends FdfsAutoConfiguration {int soTimeout;int connectTimeout;String trackerServer;public FastDfsConfig(FdfsProperties properties){super(properties);}@Beanpublic PooledConnectionFactory pooledConnectionFactory() {PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory();pooledConnectionFactory.setSoTimeout(getSoTimeout());pooledConnectionFactory.setConnectTimeout(getConnectTimeout());return pooledConnectionFactory;}@Beanpublic TrackerConnectionManager trackerConnectionManager(FdfsConnectionPool fdfsConnectionPool) {return new TrackerConnectionManager(fdfsConnectionPool, Arrays.asList(trackerServer));}
}
在common下创建类com.heima.fastdfs.FastDfsClient,封装dfs上传、下载等常用方法:
/*** dfs客服端*/
@Component
public class FastDfsClient {@AutowiredFastFileStorageClient storageClient;/*** 上传文件方法* Title: uploadFile
* Description:
* @param fileName 文件全路径* @param extName 文件扩展名,不包含(.)* @return* @throws Exception*/public String uploadFile(String fileName, String extName) throws Exception {StorePath s = storageClient.uploadFile(FileUtils.readFileToByteArray(new File(fileName)),extName);String result = s.getFullPath();return result;}public String uploadFile(String fileName) throws Exception {return uploadFile(fileName, null);}/*** 上传文件方法* Title: uploadFile
* Description:
* @param fileContent 文件的内容,字节数组* @param extName 文件扩展名* @return* @throws Exception*/public String uploadFile(byte[] fileContent, String extName) throws Exception {StorePath s = storageClient.uploadFile(fileContent,extName);String result = s.getFullPath();return result;}public String uploadFile(byte[] fileContent) throws Exception {return uploadFile(fileContent, null);}/*** 文件下载方法*/public byte[] downFile(String fileId) throws Exception {return storageClient.downloadFile("",fileId);}/*** 文件下载方法*/public byte[] downGroupFile(String group, String fileId) throws Exception {return storageClient.downloadFile(group,fileId);}public int delFile(String fileId) throws Exception {storageClient.deleteFile(fileId);return 1;}}
(1)基本定义
参考标准 | 请参考通用接口规范 |
---|---|
接口名称 | /api/v1/media/material/upload_picture |
请求DTO | MultipartFile |
响应DTO | WmMaterial |
(2) CODE定义
PARAM_INVALID | PARAM_INVALID(501,“无效参数”), |
---|---|
PARAM_IMAGE_FORMAT_ERROR | PARAM_IMAGE_FORMAT_ERROR(502,“图片格式有误”) |
SERVER_ERROR | SERVER_ERROR(503,“服务器内部错误”), |
类说明:
MultipartFile是用于接收用户上传文件
FastDFSClient用于将用户上传的图片上传至图片服务器,放置在common模块
WmMaterialMapper、WmNewsMaterialMapper是MybatisMapper文件,放置在model模块
MaterialManageControllerApi是服务接口定义,放置在apis模块
MaterialManageController、MaterialService、MaterialServiceImpl是对功能的实现,放置在media模块
(1)WmMaterial 实体
在model模块下创建类com.heima.model.media.pojos.WmMaterial
@Data
public class WmMaterial { private Integer id; @IdEncrypt private Long userId; private String url; private short type; private Short isCollection; private Date createdTime;
}
(2)WmMaterialMapper
创建类com.heima.model.mappers.wemedia.WmMaterialMapper,增加素材插入方法:
public interface WmMaterialMapper { int insert(WmMaterial record);
}
(3)WmMaterialMapper.xml
同样在model模块中创建文件resources/mappers/wemedia/WmMaterialMapper.xml,并写出接口对应sql,
保存上传图片的信息到数据库中。
insert into wm_material (user_id, url, type, is_collection, created_time ) values (#{userId}, #{url}, #{type}, #{isCollection}, #{createdTime} )
判断入参multipartFile是否合法,不合法则返回PARAM_INVALID错误
判断入参multipartFile是否有合法的扩展名,不合法则返回PARAM_INVALID错误
上传图片到FastDFS服务器
上传图片到服务器失败
上传图片流程完成, 返回信息给前端
(1)MaterialService
在media模块中(若模块不存在则创建模块儿)创建类:com.heima.media.service.MaterialService,并添加uploadPicture方法实现图片的上传逻辑
定义获取文章详情接口:
public interface MaterialService { /** * 上传图片接口* * @param multipartFile* * @return* */ ResponseResult uploadPicture(MultipartFile multipartFile);
}
(2)MaterialServiceImpl
同样在media中创建类:com.heima.media.service.impl.MaterialServiceImpl,在方法的实现中首先调用fastDFS实现图片上传至服务器,
然后将文件信息存储到关系型数据库中。
修改工程resources/application.properties文件,添加配置
FILE_SERVER_URL=http://192.168.25.133/
实现类
@Service
@Slf4j
public class MaterialServiceImpl implements MaterialService { @Value("${FILE_SERVER_URL}") private String fileServerUrl; @Autowired private FastDfsClient fastDFSClient; @Autowired private WmMaterialMapper wmMaterialMapper; @Override public ResponseResult uploadPicture(MultipartFile multipartFile) { WmUser user = WmThreadLocalUtils.getUser(); if (multipartFile == null) { return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID); } String originFileName = multipartFile.getOriginalFilename(); String extName = originFileName.substring(originFileName.lastIndexOf(".") +1); if(!extName.matches("(gif|png|jpg|jpeg)")) { returnResponseResult.errorResult(AppHttpCodeEnum.PARAM_IMAGE_FORMAT_ERROR); } // StringBuilder imgUrl = new StringBuilder(fileServerUrl); String fileId = null; //上传图片获得文件id try { fileId = fastDFSClient.uploadFile(multipartFile.getBytes(), extName); } catch (Exception e) { e.printStackTrace(); log.error("user {} upload file {} to fastDFS error, error info:n",user.getId(), originFileName, e.getMessage()); return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR); } //上传成功保存媒体资源到数据库 WmMaterial wmMaterial = new WmMaterial(); wmMaterial.setCreatedTime(new Date()); wmMaterial.setType((short) 0); wmMaterial.setUrl(fileId); wmMaterial.setUserId(user.getId()); wmMaterial.setIsCollection((short) 0); wmMaterialMapper.insert(wmMaterial); //设置返回值 wmMaterial.setUrl(fileServerUrl + wmMaterial.getUrl()); return ResponseResult.okResult(wmMaterial); }
}
(3)MaterialManageControllerApi
创建类:com.heima.media.apis.MaterialManageControllerApi,在此类中定义控制器接口。
此类在apis模块中创建,定义了相关接口,实现如下:
public interface MaterialManageControllerApi { /** * 上传图片* @param multipartFile* @return*/ ResponseResult uploadPicture(MultipartFile multipartFile);
}
(4)MaterialManageController
创建类:com.heima.media.controller.v1.MaterialManageController,
在控制器中调用Service中写的方法即可
该类的实现较为简单,引入Service并调用即可:
@RestController
@RequestMapping("/api/v1/media/material")
public class MaterialManageController implements MaterialManageControllerApi{ @Autowired private MaterialService materialService; @PostMapping("/upload_picture") @Override public ResponseResult uploadPicture(MultipartFile file) { return materialService.uploadPicture(file); }
}
(1)基本定义
此接口用于删除无关联的图片。
参考标准 | 请参考通用接口规范 |
---|---|
接口名称 | /api/v1/media/material/del_picture |
请求DTO | com.heima.model.media.dtos.WmMaterialDto |
响应DTO | { “host”: null, “code”: 0, “error_message”: “操作成功”, “data”: “SUCCESS” } |
(2)CODE定义
PARAM_INVALID | PARAM_INVALID(501,“无效参数”) |
---|---|
SERVER_ERROR | SERVER_ERROR(503,“服务器内部错误”), |
类说明:
涉及的pojo和Mapper都存储在model模块中
请求DTO也重用WmMaterialDto,缺少字段进行补充即可
Service、Controller等类都进行重用,定义新的方法
相关类在model模块中实现,之后所有的mapper文件、dto实体类都默认在model模块儿中进行实现,service相关接口默认在media模块中实现。
(1)WmMaterialDto
创建类com.heima.model.media.dtos.WmMaterialDto,用于接收前端传递过来的参数。
@Data
public class WmMaterialDto { @IdEncrypt private Integer id;
}
(2)WmMaterialMapper
在com.heima.model.mappers.wemedia.WmMaterialMapper类中定义方法:
public interface WmMaterialMapper { WmMaterial selectByPrimaryKey(Integer id);int deleteByPrimaryKey(Integer id);
}
(3)WmMaterialMapper.xml
在文件resources/mappers/wemedia/WmMaterialMapper.xml,在当前文件中根据业务写出对应的SQL
id, user_id, url, type, is_collection, created_time
delete from wm_material where id = #{id}
(4)WmNewsMaterialMapper
删除时,如果对应的material有关联引用,则不能删除,所以需要查询对应的引用数据:com.heima.model.mappers.wemedia.WmNewsMaterialMapper
public interface WmNewsMaterialMapper {int countByMid(Integer mid);
}
(2)WmNewsMaterialMapper.xml
在文件resources/ mappers/wemedia/WmNewsMaterialMapper.xml SQL如下:
判断行为实体参数是否存在,如果不存在则返回PARAM_REQUIRE错误
查看当前删除图片是否存在于系统中
当前图片是否被引用, 如果被引用则不可删除
删除图片服务器上面的图片
所有操作完成成功返回
(1)MaterialService
在com.heima.media.service.MaterialService 中新增方法delPicture实现图片的删除逻辑,定义获取文章详情接口:
ResponseResult delPicture(WmMaterialDto dto);
(2)MaterialServiceImpl
在类com.heima.media.service.impl.MaterialServiceImpl中实现图片资源管理。此处主要实现了图片资源的删除,删除逻辑主要分为两步第一步先删除fastDFS上面的文件,然后删除数据库中的关联关系。
@Override
public ResponseResult delPicture(WmMaterialDto dto) { WmUser user = WmThreadLocalUtils.getUser(); if (dto == null || dto.getId() == null) { return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID); } //删除fastDFS上的文件 WmMaterial wmMaterial = wmMaterialMapper.selectByPrimaryKey(dto.getId()); if (wmMaterial == null) { return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID); } int count = wmNewsMaterialMapper.countByMid(dto.getId()); if (count > 0) { return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"当前图片被引用"); } String fileId = wmMaterial.getUrl().replace(fileServerUrl, ""); try { fastDFSClient.delFile(fileId); } catch (Exception e) { e.printStackTrace(); log.error("user {} delete file {} from fastDFS error, error info:n",user.getId(), fileId, e.getMessage()); return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR); } //删除数据库记录 wmMaterialMapper.deleteByPrimaryKey(dto.getId()); return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
(3)MaterialManageControllerApi
在类com.heima.media.apis.MaterialManageControllerApi中定义图片删除接口方法。
ResponseResult delPicture(WmMaterialDto wmMaterial);
(4)MaterialManageController
在类com.heima.media.controller.v1.MaterialManageController中实现图片删除接口方法。
@PostMapping("/del_picture")
@Override
public ResponseResult delPicture(@RequestBody WmMaterialDto dto) { return materialService.delPicture(dto);
}
(1)基本定义
此接口用于加载自媒体人的图文素材,和用于图片素材选择框。
参考标准 | 请参考通用接口规范 |
---|---|
接口名称 | /api/v1/media/material/list |
请求DTO | com.heima.model.media.dtos.WmMaterialListDto |
响应DTO | {“host”: null,“code”: 0, “error_message”: “操作成功”, “data”:{size:1,total:1,list:[]}} |
(2)CODE定义
PARAM_INVALID | PARAM_INVALID(501,“无效参数”) |
---|---|
SERVER_ERROR | SERVER_ERROR(503,“服务器内部错误”), |
类说明:
涉及的pojo和Mapper都存储在model模块中
请求DTO也重用WmMaterialDto,缺少字段进行补充即可
Service、Controller等类都进行重用,定义新的方法
相关类在model模块中实现
(1)PageRequestDto
创建类com.heima.model.common.dtos.PageRequestDto,再该类中定义了checkParam方法用于校验分页参数,
若分页参数异常并给分页参数默认值。
@Data
@Slf4j
public class PageRequestDto { protected Integer size; protected Integer page; public void checkParam() { if (this.page == null || this.page < 0) { setPage(1); } if (this.size == null || this.size < 0 || this.size > 100) { setSize(10); } }
}
(2)WmMaterialListDto
创建类com.heima.model.media.dtos.WmMaterialListDto,该类继承了PageRequestDto用于实现分页参数的封装
@Data
public class WmMaterialListDto extends PageRequestDto { Short isCollected; //1 查询收藏的
}
(3)WmMaterialMapper
在类com.heima.model.mappers.wemedia.WmMaterialMapper新增接口方法findListByUidAndStatus用于根据用户id和需要查询的图片状态(是否收藏)查询图片、countListByUidAndStatus进行分页统计:
List findListByUidAndStatus(WmMaterialListDto dto, Long uid);
int countListByUidAndStatus(WmMaterialListDto dto, Long uid);
(4)WmMaterialMapper.xml
在文件resources/mappers/wemedia/WmMaterialMapper.xml中新增以下内容,对应在接口中新增的方法。
检测分页参数是否正确,如果不存在则返回PARAM_REQUIRE错误
操作成功,返回查询结果集
(1)MaterialService
在com.heima.media.service.MaterialService中新增方法findList查找图片列表的接口方法:
ResponseResult findList(WmMaterialListDto dto);
(2)MaterialServiceImpl
在com.heima.media.service.impl.MaterialServiceImpl,中实现findList方法用于实现查找图片列表
@Override
public ResponseResult findList(WmMaterialListDto dto) { dto.checkParam(); Long uid = WmThreadLocalUtils.getUser().getId(); List datas = wmMaterialMapper.findListByUidAndStatus(dto,uid); datas = datas.stream().map((item) -> { item.setUrl(fileServerUrl + item.getUrl()); return item; }).collect(Collectors.toList()); int total = wmMaterialMapper.countListByUidAndStatus(dto, uid); Map resDatas = new HashMap<>(); resDatas.put("curPage", dto.getPage()); resDatas.put("size", dto.getSize()); resDatas.put("list", datas); resDatas.put("total", total); return ResponseResult.okResult(resDatas);
}
(3)MaterialManageControllerApi
在类com.heima.media.apis.MaterialManageControllerApi中定义了相关接口,实现如下:
ResponseResult list(WmMaterialListDto dto);
(4)MaterialManageController
在类com.heima.media.controller.v1.MaterialManageController中增加对应接口方法。
@RequestMapping("/list")
@Override
public ResponseResult list(@RequestBody WmMaterialListDto dto) { return materialService.findList(dto);
}
(1)基本定义
此接口用于标记素材图片收藏、取消收藏等操作。
参考标准 | 请参考通用接口规范 |
---|---|
收藏接口名称 | /api/v1/media/material/collect |
取消收藏接口 | /api/v1/media/material/cancle_collect |
请求DTO | com.heima.model.media.dtos.WmMaterialDto |
响应DTO | {“host”: null, “code”: 0,“error_message”: “操作成功”,“data”: “SUCCESS”} |
(2)CODE定义
PARAM_INVALID | PARAM_INVALID(501,“无效参数”) |
---|---|
SERVER_ERROR | SERVER_ERROR(503,“服务器内部错误”), |
类说明:
涉及的pojo和Mapper都存储在model模块中
请求DTO也重用WmMaterialDto,缺少字段进行补充即可
Service、Controller等类都进行重用,定义新的方法
相关类在model模块中实现
(1)WmMaterialDto
创建类com.heima.model.media.dtos.WmMaterialDto,该类不会输出给前端,所以相关属性可不做混淆加密设置。
@Data
public class WmMaterialDto { @IdEncrypt private Integer id;
}
(2)WmMaterialMapper
在类com.heima.model.mappers.wemedia.WmMaterialMapper中定义按照文章ID查询内容方法:
int updateStatusByUidAndId(Integer id, Long userId, Short type);
(3)WmMaterialMapper.xml
在WmMaterialMapper.xml文件中增加以下配置
update wm_material set is_collection = #{type} where user_id = #{userId} and id = #{id}
(1)收藏时序图
判断参数是否符合要求,如果不符合在则返回PARAM_REQUIRE错误
更新当前素材的状态
所有操作完成成功返回
(2)取消收藏时序图
判断参数是否符合要求,如果不符合在则返回PARAM_REQUIRE错误
更新当前素材的状态
所有操作完成成功返回
(1)MaterialService
在类com.heima.media.service.MaterialService中定义修改素材收藏状态的接口:
ResponseResult changeUserMaterialStatus(WmMaterialDto dto, Short type);
(2)MaterialServiceImpl
在类com.heima.media.service.impl.MaterialServiceImpl中增加素材收藏或取消方法。
@Override
public ResponseResult changeUserMaterialStatus(WmMaterialDto dto, Shorttype) { if (dto == null || dto.getId() == null) { return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID); } WmUser user = WmThreadLocalUtils.getUser(); wmMaterialMapper.updateStatusByUidAndId(dto.getId(), user.getId(), type); return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS); }
(3)MaterialManageControllerApi
在类com.heima.media.apis.MaterialManageControllerApi中定义了相关接口方法:
ResponseResult collectionMaterial(WmMaterialDto dto);ResponseResult cancleCollectionMaterial(WmMaterialDto dto);
(4)MaterialManageController
定义常量:com.heima.common.media.constans.WmMediaConstans
public class WmMediaConstans {public static final Short COLLECT_MATERIAL= 1; //收藏public static final Short CANCEL_COLLECT_MATERIAL = 0; //取消收藏public static final String WM_NEWS_TYPE_IMAGE = "image";public static final Short WM_NEWS_DRAFT_STATUS = 0; //草稿public static final Short WM_NEWS_SUMMIT_STATUS = 1; //提交public static final Short WM_NEWS_AUTHED_STATUS = 8; //审核通过public static final Short WM_NEWS_PUBLISH_STATUS = 9; //已发布public static final Short WM_NEWS_NONE_IMAGE = 0; //无图public static final Short WM_NEWS_SINGLE_IMAGE = 1; //单图public static final Short WM_NEWS_MANY_IMAGE = 3; //多图public static final Short WM_NEWS_TYPE_AUTO = -1; //图文类型自动public static final Short WM_CONTENT_REFERENCE = 0;public static final Short WM_IMAGE_REFERENCE = 1;public static final char WM_NEWS_IMAGES_SWPARATOR = ',';public static final short WM_NEWS_STATISTIC_CUR = 0; //查询当日public static final short WM_NEWS_STATISTIC_WEEK = 1; //查询近一周public static final short WM_NEWS_STATISTIC_NEAR7 = 7; //查询近七天public static final short WM_NEWS_STATISTIC_NEWA30 = 30; //查询近30天}
在类com.heima.media.controller.v1.MaterialManageController中增加对应接口方法。
@PostMapping("/collect")
@Override
public ResponseResult collectionMaterial(@RequestBody WmMaterialDto dto) { return materialService.changeUserMaterialStatus(dto,WmMediaConstans.COLLECT_MATERIAL);
} @PostMapping("/cancel_collect")
@Override
public ResponseResult cancleCollectionMaterial(@RequestBody WmMaterialDtodto) { return materialService.changeUserMaterialStatus(dto,WmMediaConstans.CANCEL_COLLECT_MATERIAL); }
导入资料文件夹中的heima-leadnews-wemedia项目,使用web strom打开
(1)图片列表
export const API_USERIMAGES_LIST = '/api/v1/media/material/list'
//拉取全部的素材图片
export function getAllImgData (data) { return Request({ url:API_USERIMAGES_LIST, method:'post', params:{}, data:data })
}
(2)删除图片
export const API_MODIFYIMAGE_DELETE ='/api/v1/media/material/del_picture' //删除图片
//删除图片素材
export function delImg (id) { return Request({ url:API_MODIFYIMAGE_DELETE, method:'post', params:{}, data:{id:id} })
}
(3)收藏或取消收藏图片
export const API_MODIFYIMAGE_COL = '/api/v1/media/material/collect'
//收藏用户素材 或 修改收藏状态接
export const API_MODIFYIMAGE_COL_CANCEL = '/api/v1/media/material/cancel_collect' //取消用户素材 或 修改收藏状态接口
//收藏或取消收藏方法
export function collectOrCancel (id,data) { let collect = data.isCollected let url = API_MODIFYIMAGE_COL if(collect==0){ url = API_MODIFYIMAGE_COL_CANCEL } return Request({ url:url, method:'post', params:{}, data:{id:id} })
}
(4)上传图片
export const API_USERIMAGES_ADD ='/api/v1/media/material/upload_picture'
//上传图片
export function uploadImg (data) { return Request({ url:API_USERIMAGES_ADD, method:'post', data })
}
在src/router.js中asyncRouterMap对象的children数组中增加以下改动,以满足全局自动记录路由的功能:
{ path:'/material/list', component: () => import('./views/material/material.vue'),
}
在src/constants/menus.js中的MenuData添加一下内容,
此处我们添加了我们之后将实现的所有菜单功能,此后将不再重复编写。
//导出菜单数据
export const MenuData = [ { title:'首页',path : '/' ,icon:'el-icon-s-home' }, { title:'内容管理',path:'/article',icon:'el-icon-edit', children:[ { title:'图文数据' , path : '/material/data'}, { title:'发布文章' , path : '/article/publish'}, { title:'内容列表' , path : '/article/list'}, { title:'评论列表' , path : '/comment/list'}, { title:'素材管理' , path : '/material/list'} ] }, { title:'粉丝管理', path:'/fans',icon:'el-icon-user', children:[ { title:'粉丝概况' , path : '/fans/index'}, { title:'粉丝画像' , path : '/fans/info'}, { title:'粉丝列表' , path : '/fans/list'} ] }, { title:'账户信息',path:'/user/center',icon:'el-icon-setting'}
]
(1)上传组件定义
在src/components/Upload/中创建文件upload.vue, 并实现一下代码
![]()
点击选择图片 开始上传
(2)素材管理界面定义
在src/views/material/中定义material.vue, 代码如下
图片管理 全部 收藏 上传图片 ![]()
![]()
![]()
关闭
(1)基本定义
保存文章信息为草稿或发布文章
参考标准 | 请参考通用接口规范 |
---|---|
发布接口名称 | /api/v1/media/news/submit |
草稿接口名称 | /api/v1/media/news/submit |
请求DTO | com.heima.model.media.dtos.WmNewsDto |
响应DTO | { “host”: null, “code”: 0, “error_message”: “操作成功”, “data”: “SUCCESS” } |
查询所有的channel
参考标准 | 请参考通用接口规范 |
---|---|
发布接口名称 | /api/v1/channel/channels |
请求DTO | 无 |
响应DTO | { “host”: null, “code”: 0, “error_message”: “操作成功”, “data”: List } |
(2)CODE定义
PARAM_INVALID | PARAM_INVALID(501,“无效参数”), |
---|---|
PARAM_REQUIRE | PARAM_REQUIRE(500,“缺少参数”) |
(3)思路分析
如果用户传递参数为空或文章内容为空返回PARAM_REQUIRE错误
如果用户本次为修改操作那么先删除数据库中的信息
保存或修改文章的数据
保存内容中的图片和当前文章的关系
保存封面图片和当前文章的关系
流程处理完成返回处理结果
(1)WmMaterialMapper
在类com.heima.model.mappers.wemedia.WmMaterialMapper中定义findMaterialByUidAndimgUrls方法用过用户id以及图片url查询所有的Material:
List findMaterialByUidAndimgUrls(Long uid,
Collection
WmMaterialMapper.xml
在文件resources/mappers/wemedia/WmMaterialMapper.xml,实现对应的SQL
(2)WmNewsMaterialMapper
在com.heima.model.mappers.wemedia.WmNewsMaterialMapper接口中添加delByNewsId方法用于根据id删除文章、saveRelationsByContent用于保存文章和图片的关联关系。
int delByNewsId(Integer nid);
void saveRelationsByContent(Map materials, Integer newsId,Short type);
WmNewsMaterialMapper.xml
在文件resources/ mappers/wemedia/WmNewsMaterialMapper.xml 中实现如下SQL如下:
insert into wm_news_material (material_id, news_id, type, ord) values (#{mid}, #{newsId}, #{type}, #{ord})
delete from wm_news_material where news_id = #{nid}
(3)WmNewsMapper
WmNews实体类
@Data
public class WmNews {private Integer id;@IdEncryptprotected Long userId;private String title;private Short type;@IdEncryptprivate Integer channelId;private String labels;private Date createdTime;private Date submitedTime;private Short status;private Date publishTime;private String reason;@IdEncryptprivate Integer articleId;private String content;private String images; //图片用逗号分隔
}
在com.heima.model.mappers.wemedia.WmNewsMapper中添加接口方法insertNewsForEdit用于实现保存文章的操作、updateByPrimaryKey用于实现更新操作。
public interface WmNewsMapper {/*** 根据主键修改* @param dto* @return*/int updateByPrimaryKey(WmNews record);/*** 添加草稿新闻* @param dto* @return*/int insertNewsForEdit(WmNews dto);
}
WmNewsMapper.xml
id, user_id,content, title, type, channel_id, labels, created_time, submited_time, status,enable,publish_time, reason, article_id, images update wm_newsset user_id = #{userId},title = #{title},type = #{type},channel_id = #{channelId},labels = #{labels},created_time = #{createdTime},submited_time = #{submitedTime},status = #{status,jdbcType=TINYINT},publish_time = #{publishTime},reason = #{reason},article_id = #{articleId},content = #{content},images = #{images}where id = #{id} insert into wm_news(user_id, title, type, channel_id, labels, created_time, submited_time, status,publish_time,content)values (#{userId},#{title},#{type},#{channelId},#{labels},#{createdTime},#{submitedTime},#{status},#{publishTime}, #{content})
(4)获取所有的channel
AdChannel实体类
@Data
public class AdChannel {private Integer id;private String name;private String description;private Boolean isDefault;private Boolean status;private Byte ord;private Date createdTime;
}
定义AdChannelMapper接口:com.heima.model.mappers.admin.AdChannelMapper
public interface AdChannelMapper {/*** 查询所有*/public List selectAll();
}
AdChannelMapper.xml
id, name, description, is_default, status, ord, created_time and name = #{name} and description = #{description} and is_default = #{isDefault} and status = #{status} and ord = #{ord}
如果用户传递参数为空或文章内容为空返回PARAM_REQUIRE错误
如果用户本次为修改操作那么先删除数据库关联数据
将用户提交的文章内容解析转为Map结构的数据
保存或修改文章的数据
保存内容中的图片和当前文章的关系
保存封面图片和当前文章的关系
流程处理完成返回处理结果
(1)NewsService
创建类:com.heima.media.service.NewsService, 并添加saveNews接口方法
public interface NewsService {/** * 自媒体发布文章 * @param wmNews* @return*/ ResponseResult saveNews(WmNewsDto wmNews, Short type);
}
NewsServiceImpl
创建类:com.heima.media.service.impl.NewsServiceImpl并实现接口中的方法,在保存新闻的实现方法中分为以下步骤:
1.如果是修改先删除所有素材关联关系
2.解析文章类容,进行图文素材关联信息提取
3.保存发布文章信息
4.如果存在引用并且是提交审核则需要做关联,否则只是进行保存草稿则不进行内容素材关联操作
5.封面图片关联数据存储
@Service
@Slf4j
@SuppressWarnings("all")
public class NewsServiceImpl implements NewsService {@Autowiredprivate ObjectMapper objectMapper;@Autowiredprivate WmMaterialMapper wmMaterialMapper;@Autowiredprivate WmNewsMapper wmNewsMapper;@Autowiredprivate WmNewsMaterialMapper wmNewsMaterialMapper;@Autowiredprivate ApArticleConfigMapper apArticleConfigMapper;@Value("${FILE_SERVER_URL}")private String fileServerUrl;@Overridepublic ResponseResult saveNews(WmNewsDto dto, Short type) {if (dto == null || !StringUtils.isNotEmpty(dto.getContent())) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}WmUser user = WmThreadLocalUtils.getUser();//如果是修改先删除所有素材关联关系if (dto.getId() != null){wmNewsMaterialMapper.delByNewsId(dto.getId());}//解析文章类容,进行图文素材关联String content = dto.getContent();//Map<图片排序号, dfs文件id>Map materials;try {List
(2)查询所有的channel,定义接口:com.heima.media.service.AdChannelService
public interface AdChannelService {List selectAll();
}
AdChannelServiceImpl实现类
@Service
public class AdChannelServiceImpl implements AdChannelService {@Autowiredprivate AdChannelMapper channelMapper;@Overridepublic List selectAll() {return channelMapper.selectAll();}
}
(3)WmNewsDto
创建类:com.heima.model.media.dtos.WmNewsDto
此类在model模块中创建,定义请求入参,实现如下:
@Data
public class WmNewsDto { private Integer id; private String title; @IdEncrypt private Integer channelId; private String labels; private Date publishTime; private String content; private Short type; private Date submitedTime; private Short status; private String reason; private List images;
}
(4)NewsControllerApi
在类com.heima.media.apis.NewsControllerApi中增加summitNews、saveDraftNews方法
public interface NewsControllerApi { /** * 提交文章* * @param wmNews* * @return* */ ResponseResult summitNews(WmNewsDto wmNews); /** * 保存草稿* @param wmNews* @return*/ ResponseResult saveDraftNews(WmNewsDto wmNews);}
(5)NewsController
在com.heima.media.controller.v1.NewsController类中实现NewsControllerApi接口方法,调用对应的service接口即可。
@RestController
@RequestMapping("/api/v1/media/news")
public class NewsController implements NewsControllerApi { @Autowired private NewsService newsService; @PostMapping("/submit") @Override public ResponseResult summitNews(@RequestBody WmNewsDto wmNews) { return newsService.saveNews(wmNews,WmMediaConstans.WM_NEWS_SUMMIT_STATUS); } @PostMapping("/save_draft") @Override public ResponseResult saveDraftNews(@RequestBody WmNewsDto wmNews) { return newsService.saveNews(wmNews, WmMediaConstans.WM_NEWS_DRAFT_STATUS); }}
(6)定义api接口:com.heima.media.apis.AdChannelControllerApi
public interface AdChannelControllerApi {public ResponseResult selectAll();
}
(7)AdChannelController
@RestController
@RequestMapping("/api/v1/channel")
public class ChannelController implements AdChannelControllerApi {@Autowiredprivate AdChannelService channelService ;@Override@RequestMapping("/channels")public ResponseResult selectAll(){return ResponseResult.okResult(channelService.selectAll());}
}
???经过测试,别管是草稿还是发布审核状态都是1,草稿的状态应该为0
(1)获取所有频道
export const API_CHANNELS = '/api/v1/channel/channels' //获取文章频道
export function getChannels () { return Request({ url:API_CHANNELS, method:'get', })
}
(2)发布文章
export const API_ARTICLES = '/api/v1/media/news/submit' //post文章(新建)
//发表文章
export function publishArticles (params,data) { console.log(params,data) return Request({ url:API_ARTICLES, method:'post', params, data })
}
(3)修改文章
export const API_ARTICLES = '/api/v1/media/news/submit' //post文章(新建)
//编辑文章
export function modifyArticles (articleId,params,data) { return Request({ url:API_ARTICLES, method:'post', params, data })
}
(4)根据ID获取文章
export const API_ARTICLES_INFO = '/api/v1/media/news/news' //获取文章
//获取文章
export function getArticleById (articlesId) { return Request({ url:API_ARTICLES_INFO, method:'post', params:{}, data:{id:articlesId} })
}
在src/router.js中asyncRouterMap对象的children数组中增加以下改动,以满足全局自动记录路由的功能:
{ path:'/article/publish', component: () => import('@/views/publish/index.vue'),
}
文章内容要在不同平台上通用解析,直接使用html富文本编辑器做解析,实现成本较为之大,在黑马项目中通过JSON数组来存储文章内容数据,一个元素就是一段内容,支持文字、图片等混排以及样式的调整。
(1)黑马编辑器组件定义
在src/components/editor/中创建文件heima.vue, 并实现一下代码
{{item.value}}![]()
取 消 确 定
(2)发布页面实现
发布页面就是基本的VUE表单页面,在src/views/publish/index.vue文件中实现如下:
发表文章 单图 三图 无图 自动 点击图标选择图片![]()
点击图标选择图片![]()
提交审核 存入草稿 全部 收藏 ![]()
![]()
(1)基本定义
由于框架封装只对JSON反序列化自增ID,需要请求文章ID需要封装为DTO.
参考标准 | 请参考通用接口规范 |
---|---|
发布接口名称 | /api/v1/media/news/list |
请求DTO | com.heima.model.media.dtos.WmNewsPageReqDto |
响应DTO | {“host”:,“code”: 0,“error_message”: “操作成功”,“data”: []} |
(2)CODE定义
PARAM_INVALID | PARAM_INVALID(501,“无效参数”), |
---|---|
(1)WmNewsMapper
在类com.heima.model.mappers.wemedia.WmNewsMapper中定义selectBySelective、countSelectBySelective实现分页查询
public interface WmNewsMapper {/** * 查询根据dto条件* @param dto* @param uid* @return*/ List selectBySelective(WmNewsPageReqDto dto, Long uid); /** * 查询总数统计* @param dto* @param uid* @return*/int countSelectBySelective(WmNewsPageReqDto dto, Long uid);}
(2)WmNewsMapper.xml
在文件resources/mappers/wemedia/WmNewsMapper.xml中实现对应的SQL编写
如果用户传递参数为空返回PARAM_REQUIRE错误
检测参数是否合法
查询用户相关的图文数据
统计当前与用户相关的图文数据一共多少
流程处理完成返回处理结果
(1)NewsService
在类com.heima.media.service.NewsService中定义listByUser方法
public interface NewsService {/** * 查询发布库中当前用户文章信息* @param dto* @return*/ ResponseResult listByUser(WmNewsPageReqDto dto);
}
(2)NewsServiceImpl
在类:com.heima.media.service.impl.NewsServiceImpl中实现接口中的方法,在此处我们实现了listByUser,用于实现查询当前用户的文章
@Override
public ResponseResult listByUser(WmNewsPageReqDto dto) { if (dto == null) { return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID); } //检测参数 dto.checkParam(); Long uid = WmThreadLocalUtils.getUser().getId(); List datas = wmNewsMapper.selectBySelective(dto, uid); int total = wmNewsMapper.countSelectBySelective(dto, uid); PageResponseResult responseResult = new PageResponseResult(dto.getPage(),dto.getSize(), total); responseResult.setData(datas); responseResult.setHost(fileServerUrl); return responseResult;
}
(3)WmNewsPageReqDto
创建类:com.heima.media.mysql.core.model.dtos.WmNewsPageReqDto,此类在model模块中创建,定义请求入参,实现如下:
@Data
public class WmNewsPageReqDto extends PageRequestDto { private Short status; private Date beginPubdate; private Date endPubdate; @IdEncrypt private Integer channelId; private String keyWord;
}
(4)NewsControllerApi
在类com.heima.media.apis.NewsControllerApi中增加listByUser接口方法
/** * 用户查询* @return*/ ResponseResult listByUser(WmNewsPageReqDto dto);
(5)NewsController
在com.heima.media.controller.v1.NewsController类中实现NewsControllerApi接口方法,调用对应的service接口即可。
@RestController
@RequestMapping("/api/v1/media/news")
public class NewsController implements NewsControllerApi { @Autowired private NewsService newsService; @PostMapping("/list") @Override public ResponseResult listByUser(@RequestBody WmNewsPageReqDto dto) { return newsService.listByUser(dto); }
}
(1)基本定义
文章详情主要用于查看和编辑数据初始化.
参考标准 | 请参考通用接口规范 |
---|---|
发布接口名称 | /api/v1/media/news/news |
请求DTO | com.heima.model.media.dtos.WmNewsDto |
响应DTO | { “host”:, “code”: 0, “error_message”: “操作成功”, “data”: {} } |
(2)CODE定义
PARAM_INVALID | PARAM_INVALID(501,“无效参数”), |
---|---|
(1)WmNewsMapper
在类com.heima.model.mappers.wemedia.WmNewsMapper中定义selectNewsDetailByPrimaryKey方法:
WmNews selectNewsDetailByPrimaryKey(Integer id);
(2)WmNewsMapper.xml
在文件resources/mappers/wemedia/ WmNewsMapper.xml中编写接口对应的SQL语句
如果用户传递参数为空返回PARAM_REQUIRE错误
根据id查询当前文章
如果查询不到对应的文章则直接返回错误提示
流程处理完成返回处理结果
(1)NewsService
在类com.heima.media.service.NewsService中定义方法findWmNewsById
/*** 根据文章id查询文章* @return*/
ResponseResult findWmNewsById(WmNewsDto wmNews);
(2)NewsServiceImpl
在类com.heima.media.service.impl.NewsServiceImpl中实现对应的方法
@Override
public ResponseResult findWmNewsById(WmNewsDto dto) {if (dto == null || dto.getId() == null) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE, "文章ID不可缺少");}WmNews wmNews = wmNewsMapper.selectNewsDetailByPrimaryKey(dto.getId());if (wmNews == null) {return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "文章不存在");}ResponseResult responseResult = ResponseResult.okResult(wmNews);responseResult.setHost(fileServerUrl);return responseResult;
}
(3)NewsControllerApi
在类com.heima.media.apis.NewsControllerApi中增加summitNews、saveDraftNews方法
/** * 根据id获取文章信息 * @param id * @return */
ResponseResult wmNews(@RequestBody WmNewsDto wmNews);
(4)NewsController
在com.heima.media.controller.v1.NewsController类中实现NewsControllerApi接口方法,调用对应的service接口即可。
@PostMapping("/news")
@Override
public ResponseResult wmNews(@RequestBody WmNewsDto dto) { return newsService.findWmNewsById(dto);
}
(1)基本定义
自从对于未发布的文章进行删除操作.
参考标准 | 请参考通用接口规范 |
---|---|
发布接口名称 | /api/v1/media/news/del_news |
请求DTO | com.heima.model.media.dtos.WmNewsDto |
响应DTO | { “host”:, “code”: 0, “error_message”: “操作成功”, “data”: {} } |
(2)CODE定义
PARAM_INVALID | PARAM_INVALID(501,“无效参数”), |
---|---|
(1)WmNewsMapper
在类com.heima.model.mappers.wemedia.WmNewsMapper中定义以下方法
WmNews selectByPrimaryKey(Integer id);int deleteByPrimaryKey(Integer id);
(2)WmNewsMapper.xml
在文件resources/mappers/wemedia/ WmNewsMapper.xml中增加对应SQL实现
delete from wm_newswhere id = #{id}
如果用户传递参数为空返回PARAM_REQUIRE错误
根据id查询当前文章
如果查询不到对应的文章则直接返回错误提示
流程处理完成返回处理结果
(1)NewsService
在类com.heima.media.service.NewsService:中定义delNews方法
/** *** @param id * @return */
ResponseResult delNews(WmNewsDto wmNews);
(2)NewsServiceImpl
在类com.heima.media.service.impl.NewsServiceImpl中实现接口中方法,此处需要注意不仅仅需要删除文章数据还需要删除文章资源关联数据
@Override
public ResponseResult delNews(WmNewsDto dto) {if (dto == null || dto.getId() == null) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}WmNews wmNews = wmNewsMapper.selectByPrimaryKey(dto.getId());if (wmNews == null) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "文章不存在");}//判断是否审核通过if (WmMediaConstans.WM_NEWS_AUTHED_STATUS.equals(wmNews.getStatus()) ||WmMediaConstans.WM_NEWS_PUBLISH_STATUS.equals(wmNews.getStatus())) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "当前文章已通过审核不可删除");}//删除文章素材关联表信息wmNewsMaterialMapper.delByNewsId(wmNews.getId());//删除文章信息wmNewsMapper.deleteByPrimaryKey(wmNews.getId());return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
(3)NewsControllerApi
在类com.heima.media.apis.NewsControllerApi中增加delNews方法
/** * 删除文章 * @param id * @return */ ResponseResult delNews(@RequestBody WmNewsDto wmNews);
(4)NewsController
在com.heima.media.controller.v1.NewsController类中实现NewsControllerApi接口方法,调用对应的service接口即可。
@PostMapping("/del_news")
@Override
public ResponseResult delNews(@RequestBody WmNewsDto dto) { return newsService.delNews(dto);
}
在内容列表界面中我们主要实现了对文章的检索功能。
(1)删除文章
export const API_ARTICLES_DELETE = '/api/v1/media/news/del_news' //删除文章
export function deleteArticles (articlesId) { return Request({ url:API_ARTICLES_DELETE , method:'post', params:{}, data:{id:articlesId} })
}
(2)检索文章
export const API_SEARCHARTICELS = '/api/v1/media/news/list' //检索文章
//搜索文章
export function searchArticle (data) { return Request({ url:API_SEARCHARTICELS, method:'post', data, params:{} })
}
在src/router.js中asyncRouterMap对象的children数组中增加以下改动,以满足全局自动记录路由的功能:
{ path:'/article/list', component: () => import('./views/content/index.vue'),
}
(1)搜索工具组件定义
在src/views/content/components/中定义SearchTool.vue组件
全部图文
(2)搜索结果组件定义
在src/views/content/components/中定义SearchResult.vue
{{`共找到${total}条符合条件的内容`}} ![]()
- {{item.title}}上架下架修改删除
草稿 待审核 待人工审核 待发布 待发布 已发表 未通过审核:{item.reason} 已删除 下架 上架 - {{dateFormat(item.publish_time)}}
(3)日期处理工具
在src/utils/中定义date.js日期处理工具
function FormatDate(){}
FormatDate.prototype= {formatDate:function(date, fmt) {if (/(y+)/.test(fmt)) {fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))}let o = {'M+': date.getMonth() + 1,'d+': date.getDate(),'h+': date.getHours(),'m+': date.getMinutes(),'s+': date.getSeconds()}for (let k in o) {if (new RegExp(`(${k})`).test(fmt)) {let str = o[k] + ''fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : this.padLeftZero(str))}}return fmt},padLeftZero:function (str) {return ('00' + str).substr(str.length)},format10:function(time){return this.format13(time*1000);},format13:function(time){if(time==undefined){return ""}let date = new Date(time);return this.formatDate(date,'yyyy-MM-dd')},format13HH:function(time){if(time==undefined){return ""}let date = new Date(time);return this.formatDate(date,'yyyy-MM-dd hh:mm:ss')},// 最近几天时间getNearTime:function(AddDayCount) {var dd = new Date();return dd.getTime()-AddDayCount*24*3600000;},// 最近本周开始时间getWeekSTime:function() {var dd = new Date();dd.setDate(dd.getDate() -dd.getDay());return dd.getTime();},// 最近本周结束时间getWeekETime:function() {var dd = new Date();dd.setDate(dd.getDate() +(7-dd.getDay()));return dd.getTime();},diffTime:function(time){if(time.length==10){time = parseInt(time)*1000;}var nowDate = new Date().getTime(),oldDate = new Date(time).getTime(),diffTime = parseInt((nowDate - oldDate)/1000,10),oneMinute = 60,oneHour = 60 * oneMinute,oneDay = 24 * oneHour,oneMonth = 30 * oneDay,oneYear = 12 * oneMonth,compareArr = [oneYear,oneMonth,oneDay,oneHour,oneMinute],postfix = ['年前','个月前','天前','个小时前','分钟前','1分钟内'],diffYear,diffMonth,diffDay,diffHour,diffMinute,len=5;for(var i =0; i< len ;i++){var diff = Math.floor(diffTime/compareArr[i]);if(diff > 0){return diff + postfix[i];}else if(i === len -1 && diff === 0){return postfix[len];}}}
}
export default new FormatDate()
(4)文章列表实现
在src/views/content/中定义index.vue, 具体代码如下:
(1)基本定义
图文统计涉及时间等查询条件,因此也需要请求DTO。
参考标准 | 请参考通用接口规范 |
---|---|
发布接口名称 | /api/v1/statistics/news |
请求DTO | com.heima.model.media.dtos.StatisticDto |
响应DTO | {“host”:, “code”: 0, “error_message”: “操作成功”,“data”: {} } |
(2)CODE定义
PARAM_INVALID | PARAM_INVALID(501,“无效参数”), |
---|---|
(1)WmNewsStatisticsMapper
创建类com.heima.model.mappers.wemedia.WmNewsStatisticsMapper:并定义findByTimeAndUserId根据时间和用户ID查询相关数据
public interface WmNewsStatisticsMapper { List findByTimeAndUserId(String burst, Long userId,StatisticDto dto);
}
WmNewsStatisticsMapper.xml
创建文件resources/mappers/wemedia/ WmNewsStatisticsMapper
id, user_id, article, read_count, comment, follow, collection, forward,likes, unlikes, unfollow, created_time
(2)根据id查询用户
在WmUserMapper接口新增方法
WmUser selectById(Long id);
WmUserMapper.xml
如果用户传递参数为空返回PARAM_REQUIRE错误
查询当前用户信息
根据条件查询相应的数据
流程处理完成返回处理结果
(1)StatisticsService
创建类:com.heima.media.service.StatisticsService:
public interface StatisticsService { /** * 查找图文统计数据 * @param dto * @return */ ResponseResult findWmNewsStatistics(StatisticDto dto);
}
(2)StatisticsServiceImpl
创建类:com.heima.media.service.impl.StatisticsServiceImpl
@Service
@SuppressWarnings("all")
public class StatisticsServiceImpl implements StatisticsService {@Autowiredprivate WmNewsStatisticsMapper wmNewsStatisticsMapper;@Autowiredprivate WmUserMapper wmUserMapper;@Overridepublic ResponseResult findWmNewsStatistics(StatisticDto dto) {ResponseResult responseResult = check(dto);if (responseResult != null){return responseResult;}WmUser wmUser = queryAllUserInfo();String burst = BurstUtils.groudOne(wmUser.getApUserId());returnResponseResult.okResult(wmNewsStatisticsMapper.findByTimeAndUserId(burst,wmUser.getApUserId(), dto));}private WmUser queryAllUserInfo() {WmUser user = WmThreadLocalUtils.getUser();user = wmUserMapper.selectById(user.getId());return user;}private ResponseResult check(StatisticDto dto) {if (dto == null && dto.getType() == null) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}if (WmMediaConstans.WM_NEWS_STATISTIC_CUR != dto.getType() &&(dto.getStime() == null || dto.getEtime() == null)) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}return null;}
}
(3)StatisticDto
创建类:com.heima.media.mysql.core.model.dtos.StatisticDto
此类在model模块中创建,定义请求入参,实现如下:
@Data
public class StatisticDto {
private Short type;
private Date stime;
private Date etime;
private List time;
}
(4)StatisticsControllerApi
在类com.heima.media.apis.StatisticsControllerApi中增加方法
public interface StatisticsControllerApi { /** * 文章数据* @param dto* @return*/ public ResponseResult newsData(StatisticDto dto);
}
(5)StatisticsController
在com.heima.media.controller.v1.StatisticsController类中实现接口方法,调用对应的service接口即可。
@RestController
@RequestMapping("/api/v1/statistics")
public class StatisticsController implements StatisticsControllerApi { @Autowired private StatisticsService statisticsService; @Override @RequestMapping("/news") public ResponseResult newsData(@RequestBody StatisticDto dto) { return statisticsService.findWmNewsStatistics(dto); }
}
(1)基本定义
粉丝统计与
参考标准 | 请参考通用接口规范 |
---|---|
发布接口名称 | /api/v1/statistics/fans |
请求DTO | com.heima.model.media.dtos.StatisticDto |
响应DTO | { “host”:, “code”: 0, “error_message”: “操作成功”, “data”: {} } |
(2)CODE定义
PARAM_INVALID | PARAM_INVALID(501,“无效参数”), |
---|---|
(1)WmFansStatisticsMapper
创建类com.heima.model.mappers.wemedia.WmFansStatisticsMapper:
public interface WmFansStatisticsMapper { List findByTimeAndUserId(String burst, Long userId,StatisticDto dto);
}
(2)WmFansStatisticsMapper.xml
创建文件resources/mappers/wemedia/WmFansStatisticsMapper.xml
id, user_id, article, read_count, comment, follow, collection, forward, likes, unlikes,unfollow, created_time
如果用户传递参数为空返回PARAM_REQUIRE错误
查询当前用户信息
根据条件查询相应的数据
流程处理完成返回处理结果
(1)StatisticsService
在com.heima.media.service.StatisticsService中增加粉丝数据接口方法
/** * 用户粉丝统计数据* @param dto* @return*/
ResponseResult findFansStatistics(StatisticDto dto);
(2)StatisticsServiceImpl
在com.heima.media.service.impl.StatisticsServiceImpl类中实现接口方法
@Autowired
private WmFansStatisticsMapper wmFansStatisticsMapper;@Override
public ResponseResult findFansStatistics(StatisticDto dto) {ResponseResult responseResult = check(dto);if (responseResult != null){return responseResult;}WmUser wmUser = queryAllUserInfo();Long userId = wmUser.getApUserId();String burst = BurstUtils.groudOne(userId);List datas =wmFansStatisticsMapper.findByTimeAndUserId(burst, userId, dto);return ResponseResult.okResult(datas);
}
(3)StatisticDto
创建类:com.heima.media.mysql.core.model.dtos.StatisticDto
此类在model模块中创建,定义请求入参,实现如下:
@Data
public class StatisticDto { private Short type; private Date stime; private Date etime; private List time;
}
(4)StatisticsControllerApi
在类com.heima.media.apis.StatisticsControllerApi中增加方法
/**
* 粉丝数据*
* @param dto*
* @return*
*/
public ResponseResult fansData(@RequestBody StatisticDto dto);
(5)StatisticsController
在com.heima.media.controller.v1.StatisticsController类中实现接口方法,调用对应的service接口即可。
@Override
@RequestMapping("/fans")
public ResponseResult fansData(@RequestBody StatisticDto dto) { return statisticsService.findFansStatistics(dto);
}
图文数据界面中我们主要实现了当前用户的图文数据的统计功能,并以图表的形式进行了展示。在这里的相关页面需要使用到echarts,需要在项目中安装echarts,后页面中导入使用。
(1)查询图文数据
export const API_STATISTICS_NEWS = '/api/v1/statistics/news' //图文统计
//获取统计数据
export function getNewsStatistics(data) { return Request({ url:API_STATISTICS_NEWS, method:'post', params:{}, data:data })
}
(2)查询粉丝数据
export const API_GET_FANS_STATISTIC = '/api/v1/statistics/fans' //粉丝统计数据
//粉丝数据
export function getFansStatistics(data) {return Request({url: API_GET_FANS_STATISTIC,method: 'post',data})
}
在src/router.js中asyncRouterMap对象的children数组中增加以下改动,以满足全局自动记录路由的功能:
{ path:'/material/data', component: () => import('./views/content/detail.vue'), },{path:'/fans/index',component: () => import('./views/fans/index.vue'),}
(1)统计组件定义
在src/views/content/components/中定义Statist.vue,
实现基本数据的展示,具体代码如下:
{{article}} 个图文发布量 {{likes}} 个点赞数量 {{collection}}收藏量
(2)线形图组件定义
在src/views/content/components/中定义LineChart.vue实现数据的线图展示功能:
(3)doughnut图表组件定义
在src/views/fans/components/中定义组件DoughnutChart.vue
(4)数据统计整体实现
在src/views/content/中定义组件detail.vue
详情分析 今日 本周 近7天 近30天
(1)统计组件定义
在src/views/fans/components/index/中定义组件Statist.vue
{{article}} 个图文发布量 {{likes}} 个点赞数量 {{collection}}收藏量
(2)线形图组件定义
在 src/views/fans/components/index/中定义LineChart.vue
(3)doughnut图表组件定义
在src/views/fans/components/index/中定义DoughnutChart.vue
(4)数据统计整体实现
在src/views/fans/中定义index.vue
详情分析 今日 本周 近7天 近30天