1.项目简介
1.1 微头条业务简介
微头条新闻发布和浏览平台,主要包含业务如下
-
用户功能
-
注册功能
-
登录功能
-
-
头条新闻
-
新闻的分页浏览
-
通过标题关键字搜索新闻
-
查看新闻详情
-
新闻的修改和删除
-
-
权限控制
-
用户只能修改和自己发布的头条新闻
-
1.2 技术栈介绍
前端技术栈
-
ES6作为基础JS语法
-
nodejs用于运行环境
-
npm用于项目依赖管理工具
-
vite用于项目的构建架工具
-
Vue3用于项目数据的渲染框架
-
Axios用于前后端数据的交互
-
Router用于页面的跳转
-
Pinia用于存储用户的数据
-
LocalStorage作为用户校验token的存储手段
-
Element-Plus提供组件
后端技术栈
-
JAVA作为开发语言,版本为JDK17
-
Tomcat作为服务容器,版本为10.1.7
-
Mysql8用于项目存储数据
-
Servlet用于控制层实现前后端数据交互
-
JDBC用于实现数据的CURD
-
Druid用于提供数据源的连接池
-
MD5用于用户密码的加密
-
Jwt用于token的生成和校验
-
Jackson用于转换JSON
-
Filter用于用户登录校验和跨域处理
-
Lombok用于处理实体类
1.3 功能展示
头条首页信息搜索
登录功能
注册功能
权限控制功能
发布头条功能
修改头条功能
删除头条功能
2.前端项目环境搭建
-
解压前端项目代码并存放到磁盘的合适位置
-
使用vscode打开工程
-
进入项目后打开集成终端或者在src上右击选择在集成终端中打开
-
通过 npm run dev启动前端项目
3.后端项目环境搭建
3.1 数据库准备
news_users
用户表
news_type
新闻类型表
news_headline
新闻信息表
数据库创建SQL
-
导入资料中的top_news.sql文件即可
3.2 MVC项目架构模式
MVC(Model View Controller)是软件工程中的一种
软件架构模式
,它把软件系统分为模型
、视图
和控制器
三个基本部分。用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
-
M:Model 模型层,具体功能如下
-
存放和数据库对象的实体类以及一些用于存储非数据库表完整相关的VO对象
-
存放一些对数据进行逻辑运算操作的的一些业务处理代码
-
-
V:View 视图层,具体功能如下
-
存放一些视图文件相关的代码 html css js等
-
在前后端分离的项目中,后端已经没有视图文件,该层次已经衍化成独立的前端项目
-
-
C:Controller 控制层,具体功能如下 1. 接收客户端请求,获得请求数据
-
将准备好的数据响应给客户端
-
MVC模式下,项目中的常见包
-
M:
-
实体类包(pojo /entity /bean) 专门存放和数据库对应的实体类和一些VO对象
-
数据库访问包(dao/mapper) 专门存放对数据库不同表格CURD方法封装的一些类
-
服务包(service) 专门存放对数据进行业务逻辑预算的一些类
-
-
C:
-
控制层包(controller)
-
-
V:
-
web目录下的视图资源 html css js img 等
-
前端工程化后,在后端项目中已经不存在了
-
3.3 工具类介绍
3.3.1 异步响应规范格式类
-
Result类
package com.atguigu.headline.common;
/**
* 全局统一返回结果类
*
*/
public class Result<T> {
// 返回码
private Integer code;
// 返回消息
private String message;
// 返回数据
private T data;
public Result(){}
// 返回数据
protected static <T> Result<T> build(T data) {
Result<T> result = new Result<T>();
if (data != null)
result.setData(data);
return result;
}
public static <T> Result<T> build(T body, Integer code, String message) {
Result<T> result = build(body);
result.setCode(code);
result.setMessage(message);
return result;
}
public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
Result<T> result = build(body);
result.setCode(resultCodeEnum.getCode());
result.setMessage(resultCodeEnum.getMessage());
return result;
}
/**
* 操作成功
* @param data baseCategory1List
* @param <T>
* @return
*/
public static<T> Result<T> ok(T data){
Result<T> result = build(data);
return build(data, ResultCodeEnum.SUCCESS);
}
public Result<T> message(String msg){
this.setMessage(msg);
return this;
}
public Result<T> code(Integer code){
this.setCode(code);
return this;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
-
ResultCodeEnum 枚举类
package com.atguigu.headline.common;
/**
* 统一返回结果状态信息类
*
*/
public enum ResultCodeEnum {
SUCCESS(200,"success"),
USERNAME_ERROR(501,"usernameError"),
PASSWORD_ERROR(503,"passwordError"),
NOTLOGIN(504,"notLogin"),
USERNAME_USED(505,"userNameUsed")
;
private Integer code;
private String message;
private ResultCodeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
3.3.2 MD5加密工具类
package com.atguigu.headline.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public final class MD5Util {
public static String encrypt(String strSrc) {
try {
char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f' };
byte[] bytes = strSrc.getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes);
bytes = md.digest();
int j = bytes.length;
char[] chars = new char[j * 2];
int k = 0;
for (int i = 0; i < bytes.length; i++) {
byte b = bytes[i];
chars[k++] = hexChars[b >>> 4 & 0xf];
chars[k++] = hexChars[b & 0xf];
}
return new String(chars);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("MD5加密出错!!+" + e);
}
}
}
3.3.3 JDBCUtil连接池工具类
package com.atguigu.headline.util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JDBCUtil {
private static ThreadLocal<Connection> threadLocal =new ThreadLocal<>();
private static DataSource dataSource;
// 初始化连接池
static{
// 可以帮助我们读取.properties配置文件
Properties properties =new Properties();
InputStream resourceAsStream = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
try {
properties.load(resourceAsStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/*1 向外提供连接池的方法*/
public static DataSource getDataSource(){
return dataSource;
}
/*2 向外提供连接的方法*/
public static Connection getConnection(){
Connection connection = threadLocal.get();
if (null == connection) {
try {
connection = dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
threadLocal.set(connection);
}
return connection;
}
/*定义一个归还连接的方法 (解除和ThreadLocal之间的关联关系) */
public static void releaseConnection(){
Connection connection = threadLocal.get();
if (null != connection) {
threadLocal.remove();
// 把连接设置回自动提交的连接
try {
connection.setAutoCommit(true);
// 自动归还到连接池
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
-
添加jdbc.properties配置文件
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/top_news
username=root
password=root
initialSize=5
maxActive=10
maxWait=1000
3.3.4 JwtHelper工具类
package com.atguigu.headline.util;
import com.alibaba.druid.util.StringUtils;
import io.jsonwebtoken.*;
import java.util.Date;
public class JwtHelper {
private static long tokenExpiration = 24*60*60*1000;
private static String tokenSignKey = "123456";
//生成token字符串
public static String createToken(Long userId) {
String token = Jwts.builder()
.setSubject("YYGH-USER")
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.claim("userId", userId)
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}
//从token字符串获取userid
public static Long getUserId(String token) {
if(StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer)claims.get("userId");
return userId.longValue();
}
//判断token是否有效
public static boolean isExpiration(String token){
try {
boolean isExpire = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token)
.getBody()
.getExpiration().before(new Date());
//没有过期,有效,返回false
return isExpire;
}catch(Exception e) {
//过期出现异常,返回true
return true;
}
}
}
3.3.5 JSON转换的WEBUtil工具类
package com.atguigu.headline.util;
import com.atguigu.headline.common.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.text.SimpleDateFormat;
public class WebUtil {
private static ObjectMapper objectMapper;
// 初始化objectMapper
static{
objectMapper=new ObjectMapper();
// 设置JSON和Object转换时的时间日期格式
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
}
// 从请求中获取JSON串并转换为Object
public static <T> T readJson(HttpServletRequest request,Class<T> clazz){
T t =null;
BufferedReader reader = null;
try {
reader = request.getReader();
StringBuffer buffer =new StringBuffer();
String line =null;
while((line = reader.readLine())!= null){
buffer.append(line);
}
t= objectMapper.readValue(buffer.toString(),clazz);
} catch (IOException e) {
throw new RuntimeException(e);
}
return t;
}
// 将Result对象转换成JSON串并放入响应对象
public static void writeJson(HttpServletResponse response, Result result){
response.setContentType("application/json;charset=UTF-8");
try {
String json = objectMapper.writeValueAsString(result);
response.getWriter().write(json);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}