[JavaWeb]微头条项目

完整笔记和项目代码:
https://pan.baidu.com/s/1PZBO0mfpwDPic4Ezsk8orA?pwd=wwp5 提取码: wwp5

JavaWeb-微头条项目开发

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 后端项目结构

创建Web项目

在这里插入图片描述

导入依赖

在这里插入图片描述

准备包结构

在这里插入图片描述

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

2 项目框架源码和注解

2.1 工具类

2.1.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;
    }
}

2.1.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);
        }
    }
}

2.1.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

2.1.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;
        }
    }
}

2.1.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);
        }
    }
}

2.2 实体类和VO对象

2.2.1 NewsUser

package com.atguigu.headline.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class NewsUser implements Serializable {
   
   
    private Integer uid;
    private String username;
    private String userPwd;
    private String nickName;
}

2.2.2 NewsType

package com.atguigu.headline.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class NewsType implements Serializable {
   
   
    private Integer tid;
    private String tname;
}

2.2.3 NewsHeadline

package com.atguigu.headline.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class NewsHeadline implements Serializable {
   
   
    private Integer hid;
    private String title;
    private String article;
    private Integer type;
    private Integer publisher;
    private Integer pageViews;
    private Date createTime;
    private Date updateTime;
    private Integer isDeleted;

}

2.2.4 HeadlineQueryVo

package com.atguigu.headline.pojo.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class HeadlineQueryVo implements Serializable {
   
   
    private String keyWords;
    private Integer type ;
    private Integer pageNum;
    private Integer pageSize;
}

2.2.5 HeadlinePageVo

package com.atguigu.headline.pojo.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class HeadlinePageVo implements Serializable {
   
   
    private Integer hid;
    private String title;
    private Integer type;
    private Integer pageViews;
    private Long pastHours;
    private Integer publisher;
}

2.2.6 HeadlineDetailVo

package com.atguigu.headline.pojo.vo;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class HeadlineDetailVo implements Serializable {
   
   
    private Integer hid;
    private String title;
    private String article;
    private Integer type;
    private String typeName;
    private Integer pageViews;
    private Long pastHours;
    private Integer publisher;
    private String author;
}

2.3 Dao层

在这里插入图片描述

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

注意,所有的Dao接口的实现类都要继承BaseDao

2.3.1 BaseDao

package com.atguigu.headline.dao;


import com.atguigu.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++
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值