【JavaWeb】头条新闻纯JavaWeb项目实现 项目搭建 数据库工具类导入 跨域问题 Postman 第一期 (前端Vue3+Vite)

文章目录

  • 一、项目简介
    • 1.1 微头条业务简介
    • 1.2 技术栈介绍
  • 二、项目部署
  • 三、准备工具类
    • 3.1 异步响应规范格式类
    • 3.2 MD5加密工具类
    • 3.3 JDBCUtil连接池工具类
    • 3.4 JwtHelper工具类
    • 3.4 JSON转换的WEBUtil工具类
  • 四、准备各层的接口和实现类
    • 4.1 准备实体类和VO对象
    • 4.2 DAO层接口和实现类
    • 4.3 Service层接口和实现类
    • 4.4 Controller层接口和实现类
      • 4.4.1 PortalController
  • 五、开发跨域CORS过滤器
    • 5.1 什么是跨域
    • 5.2 为什么会产生跨域
    • 5.3 如何解决跨域
  • 六、PostMan测试工具
    • 6.1 什么是PostMan
    • 6.2 下载PostMan
    • 6.3 怎么使用PostMan
  • 总结
    • 更新数据库存储的数据时间


一、项目简介

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用于处理实体类

二、项目部署

后端项目搭建:
2

  • controller 控制层代码,主要由Servlet组成
  • service 服务层代码,主要用于处理业务逻辑
  • dao 数据访问层,主要用户定义对于各个表格的CURD的方法
  • pojo 实体类层,主要用于存放和数据库对应的实体类以及一些VO对象
  • util 工具类包,主要用存放一些工具类
  • common 公共包,主要用户存放一些其他公共代码
  • filters 过滤器包,专门用于存放一些过滤器
  • test 测试代码包,专门用于定义一些测试的功能代码,上线前应该删掉,后期用maven可以自动处理掉

三、准备工具类

3.1 异步响应规范格式类

  • Result类
    • 针对返回结果规则的定义与限制
package com.doug.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.doug.headline.common;/*** 统一返回结果状态信息类**/
public enum ResultCodeEnum {/*** 自定义业务码 成功 200*/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.2 MD5加密工具类

package com.doug.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 JDBCUtil连接池工具类

package com.doug.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.4 JwtHelper工具类

  • 生成token口令
package com.doug.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字符串获取useridpublic 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());//没有过期,有效,返回falsereturn isExpire;}catch(Exception e) {//过期出现异常,返回truereturn true;}}
}

3.4 JSON转换的WEBUtil工具类

package com.doug.headline.util;import com.doug.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;// 初始化objectMapperstatic{objectMapper=new ObjectMapper();// 设置JSON和Object转换时的时间日期格式objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));}// 从请求中获取JSON串并转换为Objectpublic 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);}}
}

四、准备各层的接口和实现类

4.1 准备实体类和VO对象

4.1
vo : value object 针对分页查询的对象
HeadlineQueryVo : 多页查询需要的数据

4.2 DAO层接口和实现类

4.2

BaseDao基础类,封装了公共的查询方法和公共的增删改方法

package com.doug.headline.dao;import com.doug.headline.util.JDBCUtil;
import java.lang.reflect.Field;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;public class BaseDao {// 公共的查询方法  返回的是单个对象public <T> T baseQueryObject(Class<T> clazz, String sql, Object ... args) {T t = null;Connection connection = JDBCUtil.getConnection();PreparedStatement preparedStatement = null;ResultSet resultSet = null;int rows = 0;try {// 准备语句对象preparedStatement = connection.prepareStatement(sql);// 设置语句上的参数for (int i = 0; i < args.length; i++) {preparedStatement.setObject(i + 1, args[i]);}// 执行 查询resultSet = preparedStatement.executeQuery();if (resultSet.next()) {t = (T) resultSet.getObject(1);}} catch (Exception e) {throw new RuntimeException(e);} finally {if (null != resultSet) {try {resultSet.close();} catch (SQLException e) {throw new RuntimeException(e);}}if (null != preparedStatement) {try {preparedStatement.close();} catch (SQLException e) {throw new RuntimeException(e);}}JDBCUtil.releaseConnection();}return t;}// 公共的查询方法  返回的是对象的集合public <T> List<T> baseQuery(Class clazz, String sql, Object ... args){List<T> list =new ArrayList<>();Connection connection = JDBCUtil.getConnection();PreparedStatement preparedStatement=null;ResultSet resultSet =null;int rows = 0;try {// 准备语句对象preparedStatement = connection.prepareStatement(sql);// 设置语句上的参数for (int i = 0; i < args.length; i++) {preparedStatement.setObject(i+1,args[i]);}// 执行 查询resultSet = preparedStatement.executeQuery();ResultSetMetaData metaData = resultSet.getMetaData();int columnCount = metaData.getColumnCount();// 将结果集通过反射封装成实体类对象while (resultSet.next()) {// 使用反射实例化对象Object obj =clazz.getDeclaredConstructor().newInstance();for (int i = 1; i <= columnCount; i++) {String columnName = metaData.getColumnLabel(i);Object value = resultSet.getObject(columnName);// 处理datetime类型字段和java.util.Data转换问题if(value.getClass().equals(LocalDateTime.class)){value= Timestamp.valueOf((LocalDateTime) value);}Field field = clazz.getDeclaredField(columnName);field.setAccessible(true);field.set(obj,value);}list.add((T)obj);}} catch (Exception e) {throw new RuntimeException(e);} finally {if (null !=resultSet) {try {resultSet.close();} catch (SQLException e) {throw new RuntimeException(e);}}if (null != preparedStatement) {try {preparedStatement.close();} catch (SQLException e) {throw new RuntimeException(e);}}JDBCUtil.releaseConnection();}return list;}// 通用的增删改方法public int baseUpdate(String sql,Object ... args) {// 获取连接Connection connection = JDBCUtil.getConnection();PreparedStatement preparedStatement=null;int rows = 0;try {// 准备语句对象preparedStatement = connection.prepareStatement(sql);// 设置语句上的参数for (int i = 0; i < args.length; i++) {preparedStatement.setObject(i+1,args[i]);}// 执行 增删改 executeUpdaterows = preparedStatement.executeUpdate();// 释放资源(可选)} catch (SQLException e) {throw new RuntimeException(e);} finally {if (null != preparedStatement) {try {preparedStatement.close();} catch (SQLException e) {throw new RuntimeException(e);}}JDBCUtil.releaseConnection();}// 返回的是影响数据库记录数return rows;}
}

4.3 Service层接口和实现类

在这里插入图片描述

4.4 Controller层接口和实现类

4.4

BaseController 用于将路径关联到处理方法的基础控制器

  • 所有的Controller都要继承该类
package com.doug.headline.controller;import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;
import java.lang.reflect.Method;public class BaseController extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 响应的MIME类型和乱码问题resp.setContentType("application/json;charset=UTF-8");String requestURI = req.getRequestURI();String[] split = requestURI.split("/");String methodName =split[split.length-1];// 通过反射获取要执行的方法Class clazz = this.getClass();try {Method method=clazz.getDeclaredMethod(methodName,HttpServletRequest.class,HttpServletResponse.class);// 设置方法可以访问method.setAccessible(true);// 通过反射执行代码method.invoke(this,req,resp);} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e.getMessage());}}
}

4.4.1 PortalController

  • Portal 门户
/*** @Description: * 	门户 控制器 * 	即 当用户没有登录时候 所看到的页面(首页)* 	不需要做增删改查门户页请求都在这*/
@WebServlet("/portal")
public class PortalController extends BaseController{
}

五、开发跨域CORS过滤器

5.1 什么是跨域

  • 同源策略Same origin policy)是浏览器最核心也最基本的安全功能,
  • 如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。
  • 可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
  • 同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。
  • 所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号

5.2 为什么会产生跨域

  • 前后端分离模式下,客户端请求前端服务器获取视图资源,
  • 然后客户端自行向后端服务器获取数据资源,
  • 前端服务器的 协议,IP和端口和后端服务器很可能是不一样的,这样就产生了跨域

5.2

即:
前后端分离项目中:

  1. 浏览器 访问 前端服务器 获取视图资源
  2. 浏览器 访问 后端服务器 获取数据资源
  3. 访问中 前端 和 后端 服务器的 协议 IP 端口 可能不同
  4. 导致跨域问题(报错 发送数据失败)

5.3 如何解决跨域

前端项目代理模式处理 :
1
后端跨域过滤器方式处理
5.3

  • CrosFilter过滤器
package com.doug.headline.filters;import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;@WebFilter("/*")
public class CrosFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletResponse response = (HttpServletResponse) servletResponse;HttpServletRequest request =(HttpServletRequest) servletRequest;response.setHeader("Access-Control-Allow-Origin", "*");response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, HEAD");response.setHeader("Access-Control-Max-Age", "3600");response.setHeader("Access-Control-Allow-Headers", "access-control-allow-origin, authority, content-type, version-info, X-Requested-With");// 非预检请求,放行即可,预检请求,则到此结束,不需要放行if(!request.getMethod().equalsIgnoreCase("OPTIONS")){filterChain.doFilter(servletRequest, servletResponse);}}
}
  • 之后用SpringMVC框架,一个@CrossOrigin 就可以解决跨域问题了

六、PostMan测试工具

6.1 什么是PostMan

  • Postman是一个 接口测试工具 ,
  • 在做接口测试的时候,Postman相当于一个客户端,
  • 它可以模拟用户发起的各类HTTP请求,将请求数据发送至服务端,获取对应的响应结果, 从而验证响应中的结果数据是否和预期值相匹配;
  • 并确保开发人员能够及时处理接口中的bug,进而保证产品上线之后的稳定性和安全性。
  • 它主要是用来模拟各种HTTP请求的(如:get/post/delete/put…等等),
  • Postman与浏览器的区别在于有的浏览器不能输出Json格式,而Postman更直观接口返回的结果。

6.2 下载PostMan

官网下载地址: https://www.getpostman.com

6.3 怎么使用PostMan

6.2

不使用postman , 用浏览器获取 响应JSON数据,比较麻烦
1

  • 使用Postman 点击 send 后直接显示 比较方便
    • 就是模拟浏览器接收响应信息
      6.3

总结

更新数据库存储的数据时间

修改为当前时间:
UPDATE news_headline SET create_time=NOW(),update_time=NOW();
2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/450127.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Day17、18、19学习记录

#c语言知识 内存管理 1.作用域 &#xff08;1&#xff09;代码块作用域&#xff08;代码块是{}之间的一段代码&#xff09; &#xff08;2&#xff09;函数作用域 &#xff08;3&#xff09;文件作用域 2.局部变量&#xff08;自动变量auto&#xff09;&#xff1a; 在函…

快速理解复杂系统组成学习内容整合

目录 一、复杂系统组成 二、接入系统 (Access System) 三、应用系统 (Application System) 四、基础平台 (Foundation Platform) 五、中间件 (Abundant External Middleware) 六、支撑系统 (Supporting System) 参考文章 一、复杂系统组成 复杂系统是由多个相互关联、相…

2024程序员就业咋办?

国际研究机构Gartner会在每年10月份左右发布下一年度的战略发展趋势预测&#xff0c;并在次年3月左右发布和网络安全相关的趋势预测。绿盟科技通过将近3年的趋势预测进行分组对比分析后发现&#xff0c;除了众人皆知的AI技术应用外&#xff0c;数据模块化、身份优先安全、行业云…

【Java程序设计】【C00207】基于(JavaWeb+SSM)的宠物领养管理系统(论文+PPT)

基于&#xff08;JavaWebSSM&#xff09;的宠物领养管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于ssm的宠物领养系统 本系统分为前台系统、管理员、收养者和寄养者4个功能模块。 前台系统&#xff1a;游客打开系统…

AIGC时代企业与个人应该如何应对?

引言&#xff1a;AIGC是一种新兴的技术趋势&#xff0c;它正在为各个领域带来更多的创新和变革。未来&#xff0c;随着技术的不断进步和应用范围的扩大&#xff0c;AIGC的影响力还将不断增强。新时代下企业与个人应该如何应对呢&#xff1f; 1. 什么是AIGC&#xff1f; AIGC是…

[每日一题] 02.03 - 质因数分解

质因数分解 枚举到n的平方根&#xff08;得包括平方根&#xff09; 偶数去除 import math n int(input()) if n % 2 0:print(max(n // 2,2)) else:for i in range(3,int(math.sqrt(n)) 1,2):if n % i 0:print(max(n // i,i))

GrayLog踩坑历险记

背景 GrayLog作为ELK的替代产品&#xff0c;是新生代的日志采集框架。在一个采集节点日志的需求中&#xff0c;因为节点很多&#xff0c;产生的日志也很多&#xff0c;因此尝试了使用GrayLog进行日志的采集。下面记录一下使用GrayLog中遇到的坑和解决方案。 一、部署与启动 …

二、操作系统【6分】

一、课程内容提要 二、考情分析 三、操作系统概述 1、操作系统的功能 2、特殊的操作系统 四、进程管理 1、进程与线程的概念 2、进程的状态 3、信号量与PV操作 P是要资源 V是释放资源 互斥S初始值非0&#xff0c;一般为1&#xff0c;先p后v 同步S初始值一般为0&#xff0c…

假期2.3

第二章 引用内联重载 一&#xff0e;选择题-* 1、适宜采用inline定义函数情况是&#xff08;C&#xff09; A. 函数体含有循环语句 B. 函数体含有递归语句‘、考科一 ’ C. 函数代码少、频繁调用 D. 函数代码多、不常调用 2、假定一个函数为A(int i4, int j0) {;}, 则执行“A …

双非本科准备秋招(15.1)—— 线程状态

线程状态按照不同的角度可分为五种和六种。 五种状态&#xff1a; 在学校学的操作系统中讲过进程的五种状态&#xff0c;从操作系统的层面来看&#xff0c;线程有五大状态&#xff0c;下面是经典的牛头图。 起始态&#xff1a;语言层面创建了线程对象&#xff0c;还没有和操作…

ArrayList常见问题

ArrayList 1、ArrayList底层的实现原理是什么 2、ArrayList list new ArrayList(10)中的list扩容几次 3、如何实现数组和list之间的转换 4、ArrayList和LinkedList的区别是什么

06:原生云K8S解密|K8S集群安装部署|K8S网络插件

原生云K8S解密&#xff5c;K8S集群安装部署&#xff5c;K8S网络插件 K8SK8S集群架构图解 K8S部署仓库初始化kube-master安装计算节点的安装token管理 配置flannel网络&#xff08;master主机操作&#xff09; K8S 有大量夸主机的容器需要管理&#xff0c;快速部署应用&#xff…