[ 项目开发 1.0 ] 新闻网站的开发流程和注意事项
目录
一. 功能分析
(1)后台管理
5. 系统信息设置
6. 新闻类型管理
7. 新闻内容管理
8. 新闻统计(echars组件)
9. 用户审核封禁
10. 评论审核
11. 敏感词管理
(2)前台显示
(3)用户功能
1. 用户注册
2. 用户登录
3. 对新闻评论 点赞 收藏
4. 用户个人中心
二. 数据库设计
三. 核心注意事项
1. 新闻列表查询
(2). concat 关键字
(3). 开关组件
2. 新增新闻界面
(1) 两次封装
(2) 解决无法显示发布状态
(3)实现转载和原创的不同显示
(4) 文件上传(图片)
4.1 前端提交文件 使用elementUI组件提交文件
把之前所有添加过样式的vue中都添加上scope
4.2 后端接收文件 使用spring+Apache文件上传组件
4.3 储存文件 将文件储存在服务器中, 只返回图片在服务器中的地址,在数据库中只存储地址
(5)阿里云OSS对象存储
(6)springboot集成oss
实际开发涉及多个部分,是一项复杂的工程, 需要协同完成, 例如:
(产品部)市场调研---需求分析---产品设计---开发(研发部 技术选型 分工)---软件测试---运维
一. 功能分析
后台管理---前台显示---用户功能
(1)后台管理
1. 前后端项目搭建
2. 管理员登录
3. 管理员管理(权限)
4. 修改密码
5. 系统信息设置
用途: 维护平台信息, 数据库中只有一条记录 ,只做修改操作
维护的信息: 系统名称 logo(图片) 公司名称 电话 地址 备案号 操作人 操作时间
6. 新闻类型管理
类型(一级)
状态(启用/停用)
7. 新闻内容管理
标题 摘要 封面图 类型 内容 分类(转载/原创) 评论(是否支持) 发布状态(是否发布)
8. 新闻统计(echars组件)
统计数据(柱状图 折线图 饼状体) 地图...
9. 用户审核封禁
10. 评论审核
11. 敏感词管理
(2)前台显示
1. 首页:
按分类显示新闻
系统信息
友情链接
2. 新闻详细页面:
新闻基本内容
点赞 收藏 评论
(3)用户功能
1. 用户注册
账号 密码 头像 昵称 性别 手机号 状态(启用 禁用) 注册时间
2. 用户登录
3. 对新闻评论 点赞 收藏
4. 用户个人中心
修改个人信息
查看个人评论
查看浏览记录
二. 数据库设计
1. admin 管理员表
2. menu 菜单表
3. admin_menu 权限表
4. news_ type 新闻类型表
id name status(0-启用 1-停用 ) adminid oper_time
5. news 新闻表
id title(标题) digest(摘要) img(封面图) content(数据库text类型) typeid(新闻类型)
type(0-原创, 1-转载) link(转载链接) commenttype(是否支持评论 0-支持评论, 1-不支持)
status(发布状态 0-未发布, 1-已发布 ) adminid (操作人) oper_time(操作时间)
6. systeminfo 系统信息表
id name logo(varchar 100 给个地址) company_name phone address
filing_number(备案号) adminid oper_time
系统信息只有一条护具,可以在数据库中直接初始化一条,后期做的都是修改操作
7. link 友情链接表
id name status(0-启用,1-停用) adminid oper_time
8. sensitivewords敏感词表
id name adminid oper_time
9. user用户表
id,email(账号), password,img(头像),nick_name,gender,phone,status(0-正常,1-禁用), reg-time
三. 核心注意事项
1. 新闻列表查询
(1). <where> 标签
<where>是mybatis中的动态sql标签, 一旦where标签内部有条件成立,会自动添加where关键字, 同时可以去除where后面紧跟的关键字(例如 and)
当有前提的判断条件时(一般写法)
where a.type = 1
<if test="account!=''">
and a.account=#{account}
</if>
<if test="phone!=''">
and a.phone=#{phone}
</if>
当没有前提的判断条件时 早期的解决方法 where 1 = 1 (没有使用where标签)
where 1 = 1
<if test="title!=''">
n.title like concat('%',#{title},'%')
</if>
在mybatis 之后(使用了where标签)
<where>
<if test="title!=''">
n.title like concat('%',#{title},'%')
</if></where>
(2). concat 关键字
模糊查询中需要使用concat(字符串连接函数)
n.title like concat('%',#{title},'%')
<select id="findNewsList" resultMap="newsMap">selectn.id,n.title,n.img,t.name,n.status,n.type,a.account,n.oper_timefromnews nleft join news_type ton n.typeid = t.idleft join admin aon n.adminid = a.id<where><if test="title!=''">n.title like concat('%',#{title},'%')</if></where></select>
(3). 开关组件
可以添加在需要修改状态的地方 例如 新闻的发布状态
<template slot-scope="scope" ><el-switchv-model="scope.row.status"active-color="#13ce66"inactive-color="#ff4949"active-text="已发布"inactive-text="未发布":active-value="1":inactive-value="0" @change="changeStatus(scope.row)"></el-switch></template>
2. 新增新闻界面
(1) 两次封装
news中封装了newstype,newstype中封装了id ,为了避免冗余, 需要这么写
<el-form-item label="新闻类型">
<el-select placeholder="请选择" v-model="form.newsType.id">
<el-option
v-for="newsType in newsTypeList"
:key="newsType.id"
:label="newsType.name"
:value="newsType.id">
</el-option>
</el-select>
</el-form-item>form:{//默认封装到后端的news类里面
title:"",
digest:"",
newsType:{
id:""
},
img:"",//向后端提交的图片地址
type:0,
link:"",
commenttype:0,
content:"",
status:0
}
(2) 解决无法显示发布状态
原因: 数据类型不匹配(字符串和整数),导致前端不显示
方法一: 在label前面加冒号 " : " ,可以将字符串的0转为整数的0
<el-form-item label="是否发布">
<el-radio v-model="form.status" :label="0">发布</el-radio>
<el-radio v-model="form.status" :label="1">未发布</el-radio>
</el-form-item>
方法二: 把form表单中type 的0 加上引号 " ",这样也能接收到字符串0
form:{//默认封装到后端的news类里面
title:"",
digest:"",
newsType:{
id:""
},
img:"",//向后端提交的图片地址
type:"0",
link:"",
commenttype:0,
content:"",
status:0
}
(3)实现转载和原创的不同显示
点击转载时出现链接,点击原创时出现文本内容
方法: v-show 例如 v-show= "form.type==0"
v-if 和 v-else 如下:
<el-form-item label="类型"><el-radio v-model="form.type" :label="0">原创</el-radio><el-radio v-model="form.type" :label="1">转载</el-radio></el-form-item><el-form-item label="新闻内容" v-if="form.type==0"><mavon-editor ref="md" v-model="form.content" :toolbars="toolbars" @imgAdd="imgAdd" /></el-form-item><el-form-item label="链接转载" v-if="form.type==1"><el-input v-model="form.link" style="width: 500px"></el-input></el-form-item>
(4) 文件上传(图片)
4.1 前端提交文件 使用elementUI组件提交文件
<el-form-item label="封面图">
<!-- 使用elementUI文件上传组件 而不是axios组件发送请求
地址不能自动不全,不能自动携带token-->
<el-upload
class="avatar-uploader"
:action="serverAdd" 后端服务器地址,这里直接填入拼接后的地址
:headers="{token:token}"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload">
<img v-if="imgUrl" :src="imgUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
<style scoped>
/*加上 scoped 目的是作用在当前vue文件中*/
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 80px;
height: 80px;
line-height: 80px;
text-align: center;
}
.avatar {
width: 80px;
height: 80px;
display: block;
}
</style>
return{
//新增对话框默认是关闭的
dialogVisible:false,
newsTypeList:[],
imgUrl:"",//前端临时显示用的
token:sessionStorage.getItem("token"),//临时存储中拿到token
serverAdd:this.serverAddress+"api/newsCtl/uploadImg" ,
form:{//默认封装到后端的news类里面
title:"",
digest:"",
newsType:{
id:""
},
img:"",//向后端提交的图片地址
type:0,
link:"",
commenttype:0,
content:"",
status:0
}
}
把之前所有添加过样式的vue中都添加上scope
//图片上传成功后会自动调用 在前端临时显示图片 resp用来接收后端响应的数据
handleAvatarSuccess(resp, file) {
this.imgUrl = URL.createObjectURL(file.raw);
this.form.img = resp.data;
alert(this.form.img);
},
//文件上传前调用 文件格式验证
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上传头像图片只能是 JPG 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!');
}
return isJPG && isLt2M;
}
4.2 后端接收文件 使用spring+Apache文件上传组件
添加apache 文件上传组件依赖
<!-- 文件上传组件 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
添加spring文件解析类
package com.ffyc.news.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;@Configuration
public class MultipartConfig {/**
* 文件上传配置
* @return
*/
@Bean
public CommonsMultipartResolver multipartConfigElement() {
CommonsMultipartResolver multipartresolver = new CommonsMultipartResolver();
multipartresolver.setMaxUploadSize(1024*1024*5);
return multipartresolver;
}
}
/*** 接收上传的文件,post请求 上传到阿里云* 使用CommonsMultipartFile 直接接收到文件*/@PostMapping(path = "/uploadImg")public Result uploadImg(@RequestParam("file")CommonsMultipartFile commonsMultipartFile) throws IOException {/*System.out.println(commonsMultipartFile.getName());System.out.println(commonsMultipartFile.getOriginalFilename());*//*InputStream inputStream =commonsMultipartFile.getInputStream();//把文件写入自己的服务器地址File file = new File("D:\\development\\apache-tomcat-9.0.43\\webapps\\ROOT"+commonsMultipartFile.getOriginalFilename());commonsMultipartFile.transferTo(file);//把文件输入到指定文件*/InputStream inputStream = commonsMultipartFile.getInputStream();//使用阿里云oss对象存储//为了避免上传的文件重名,重新生成一个文件名String newFileName = new Date().getTime()+commonsMultipartFile.getOriginalFilename();//连接ossOSS ossClient = new OSSClientBuilder().build("https://"+endpoint, accessKeyId, accessKeySecret);//上传文件ossClient.putObject(bucketName, newFileName, commonsMultipartFile.getInputStream());//拼接文件在oss中访问地址String url = "https://"+bucketName+"."+endpoint+"/"+newFileName;Result result = new Result(200,"上传成功",url);return result;}
代码直接由阿里云提供, 不需要自己手写,仅理解即可,具体步骤看
(5)阿里云OSS对象存储
(6)springboot集成oss
4.3 储存文件 将文件储存在服务器中, 只返回图片在服务器中的地址,在数据库中只存储地址
原来: base64 格式字符串 ---->数据库
markdown上传图片
<el-form-item label="新闻内容" v-if="form.type==0">
<mavon-editor ref="md" v-model="form.content" :toolbars="toolbars" @imgAdd="imgAdd" />
</el-form-item>
//添加图片
imgAdd (pos, file) {
var formdata = new FormData();
formdata.append('file', file);//前端封装图片数据 ‘file’向后端传递的 name
this.$http({ //调用 java 后端上传图片到服务器端
url:this.serverAdd,//自定义后端服务器地址,后端同文件上传功能
data: formdata, method:"post", headers: { 'Content-Type': 'multipart/form-data','token':this.token} }).then((resp) => {//resp 后端响应数据
//将服务器返回的图片地址插入到编辑器内
this.$refs.md.$img2Url(pos, resp.data.data);
})
}
在新闻显示页面,添加封面图(与新增新闻的封面图不一样)
<el-table-column prop="img" label="封面图">
<template slot-scope="scope">
<img :src="scope.row.img" style="width: 50px; height: 50px;"/>
</template>
</el-table-column>
(5)阿里云OSS对象存储
访问阿里云官网
https://www.aliyun.com/
点击控制台

支付宝扫码登录,进入控制台, 没有账号注册账号

进入产品列表

选择oss对象存储

开通oss对象存储功能

完成实名认证

进入bucket列表

创建Bucket列表

创建成功,点击名称进入

测试上传文件





到此阿里云oss功能开通测试成功
(6)springboot集成oss
添加依赖
<!--阿里云oss依赖坐标-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>
spring配置文件配置
aliyun:
oss:
endpoint: 你自己阿里云账户的endpoint,例如:oss-cn-beijing.aliyuncs.com
accessKeyId: 你自己阿里云账户的accessKeyId
accessKeySecret: 你自己阿里云账户的accessKeySecret
bucketName: 你自己阿里云账户的bucketName
获取accessKeyId




在使用的类中获取配置属性值
@Value("${aliyun.oss.endpoint}")
private String endpoint;
@Value("${aliyun.oss.accessKeyId}")
private String accessKeyId;
@Value("${aliyun.oss.accessKeySecret}")
private String accessKeySecret;
@Value("${aliyun.oss.bucketName}")
private String bucketName;
代码实现
@PostMapping(path = "/uploadFile")
public CommonResult uploadFile(@RequestParam("file")
CommonsMultipartFile multipartFile) throws IOException {
//为了避免上传的文件重名,重新生成一个文件名
String newFileName = new
Date().getTime()+multipartFile.getOriginalFilename();
//连接oss
OSS ossClient = new
OSSClientBuilder().build("https://"+endpoint, accessKeyId,
accessKeySecret);
//长传文件
ossClient.putObject(bucketName, newFileName,
multipartFile.getInputStream());
//拼接文件在oss中访问地址
String url =
"https://"+bucketName+"."+endpoint+"/"+newFileName;
return new CommonResult(200, url,"操作成功");
}
上传成功


