搭建一个JavaWeb项目流程详解

搭建一个JavaWeb项目流程

本文致力于,让编程者一步步明白书写一个JavaWeb项目应该做些什么,梳理清楚流程框架,需要的jar包,同时手写了一个分页工具类也在其中,让你在编程中更加丝滑。

1.src\main\java\com\einmeer\qianyu

删除系统默认生成的HelloServlet.java

1.1tools包

DruidTools.java

需要在lib中加入druid-1.1.22.jar

package com.einmeer.qianyu.tools;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @author 芊嵛
 * @date 2024/1/18
 * JDBC操作,就是在java中操作数据库
 * 封装数据库连接工具,带连接池的
 */
public class DruidTools {
    //声明连接池对象
    private  static DruidDataSource dataSource;
    //java的静态代码块,作初始化用
    static {
        //读取外部配置文件的内容,生成字节流输入流对象
        InputStream in = DruidTools.class.getResourceAsStream("/Druid.properties");
        //创建属性集合对象
        Properties properties = new Properties();
        try {
            //加载输入流对象
            properties.load(in);
            //生成连接池对象
            dataSource= (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    //获取接池对象,便于dbutils使用,简化原生JDBC的增删改查功能CURD
    public static DruidDataSource getDataSource(){
        return  dataSource;
    }
    //拿到数据库连接对象,便于我们操作MYSQL
    public static Connection getConn() {//方便之后重复使用
        Connection conn = null;
        try {
            //创建数据库连接对象(数据库地址,用户名,密码)
            conn = dataSource.getConnection();
            System.out.println("数据库连接成功success!");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    测试一下,建议用单元测试
    public static void main(String[] args) {
        getConn();
    }
}

Pagination.java

分页,封装好了方法之后直接调用就行

package com.einmeer.qianyu.tools;

import java.util.List;

/**
 * @author 芊嵛
 * @date 2024/1/19
 */
public class Pagination<T> { // 使用泛型是为了复用
    // 当前页号
    private int currentPage;
    // 总页号或总页数
    private int totalPage;
    // 每页记录数或行数
    private int limitRows;
    // 总的记录数或行数
    private int totalRows;
    // 每页开始的记录号
    private int startRecord;
    // 每页结束的记录号,这个没用,只需每页记录行数limitRows即可
    // private int endRecord;
    // 存每页中的记录
    private List<T> list;

    // //初始化操作
    public void init() {
        // 1.求总页数,通过总记录数与每页行数来计算,有几种情况
        // (1)不够一页(2)有零头(3)刚好是整数页
        int tp = totalRows / limitRows;
        if (totalRows > limitRows) {
            // 判断是是刚刚好还是一页多一点
            totalPage = (totalRows % limitRows) == 0 ? tp : tp + 1;
        } else {
            totalPage = 1;
        }
        // 2.将当页保留在第一页或最后一页
        if (currentPage > totalPage) {
            currentPage = totalPage;
        } else if (currentPage < 1) {
            currentPage = 1;
        }
        // 3.初始化开始记录数,mysql应用的limit它不包括开始记录,所以不要加1;
        // 还有limit传入的是开始记录号与查询的条数,此处是每页可显示数limitRows,
        // 如果查到最后没有limitRows限制的行数,则显示剩余部分
        this.startRecord = (currentPage - 1) * limitRows;
    }

    // 无参构造,便于使用
    public Pagination() {
    }

    // 当前页号,总记录数,每页行数;这些属性需要传入后初始化,其它的可以set设置
    public Pagination(int currentPage, int totalRows, int limitRows) {
        this.currentPage = currentPage;
        this.totalRows = totalRows;
        this.limitRows = limitRows;
    }

    // get与set方法
    public int getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }

    public int getTotalPage() {
        return totalPage;
    }

    public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }

    public int getLimitRows() {
        return limitRows;
    }

    public void setLimitRows(int limitRows) {
        this.limitRows = limitRows;
    }

    public int getTotalRows() {
        return totalRows;
    }

    public void setTotalRows(int totalRows) {
        this.totalRows = totalRows;
    }

    public int getStartRecord() {
        return startRecord;
    }

    public void setStartRecord(int startRecord) {
        this.startRecord = startRecord;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }
}

1.2entity包

Entity层,实体层,放入实体类

详解Lombok中的@Builder用法

// Lombok注解
@Builder	// 一步步创建一个对象,它对用户屏蔽了里面构建的细节,但却可以精细地控制对象的构造过程,不写@Builder,@AllArgsConstructor会报红
@Data	// 提供了get、set、equals、toString方法
@NoArgsConstructor	// 生成一个无产构造函数
@AllArgsConstructor // 生成一个包含所有变量的有参构造函数

实现序列化

Serializable接口就是Java提供用来进行高效率的异地共享实例对象的机制,实现这个接口即可。

参考java实体类为什么要实现Serializable接口

implements Serializable

1.3dao包

DAO数据访问层,把访问数据库的代码封装起来,不涉及业务逻辑

// 接口:写需要的细分功能的名字,能用sql语句表示出来,如格局用户id查询用户全部信息
User selectUserById(Long userId);
// 实现类
//1.建议先定义一个全局结果集返回对象,应为每次运行sql语句都会返回结果
QueryRunner qr = new QueryRunner(DruidTools.getDataSource());

// 2.每个接口第一句都把返回值类型置为空(查询语句置为null)或者0(增删改置为0)
List<User> list = null;
int n = 0;

// 3.每个接口第二句写sql语句(我这里举例简单写写*号实际一定不要写*)
String sql = "select * from user where username like ? and userGander = ? limit ?,?";

// 4.创建一个对象类数组(里面放?号代替的东西,注意位置不要错)
// 如果就一个参数或者不需要参数不用写这个,多个参数再写
Object[] param = {"%"+username+"%",userGaner,start,number};

// 5.处理异常,执行sql
try {
    // 查询
    // 返回list结果集BeanListHandler<>()
    // 返回对象BeanHandler<>()
    // 返回单个数据ScalarHandler<>()
    // query(String sql, ResultSetHandler<T> rsh)
    // query(String sql, Object param, ResultSetHandler<T> rsh)
    // query(String sql, Object[] params, ResultSetHandler<T> rsh)
    // 更多可以看看源码
    list = qr.query(sql, new BeanListHandler<User>(User.class));
    user = qr.query(sql, param, new BeanHandler<>(User.class));
    // 这个看其他资料说是返回Object类型需要转,但是我测试并不需要,返回的就是我要的类型
    n = qr.query(sql,parm,new ScalarHandler<>());
    
    // 更新/删除/插入
    // update(String sql, Object param)
    // update(String sql, Object... params)
    n = qr.update(sql, username);
    n = qr.update(sql, param);
} catch (SQLException e) {
    throw new RuntimeException(e);
}

// 6.return 第一步的名字;
return list;
return n;

1.4service包

Service业务逻辑层,处理逻辑上的业务,而不去考虑具体的实现。

通过调用数据访问层,实现逻辑上的业务,一个接口的实现可能需要多个dao层的接口

// 接口:定义好方法,之后servlet直接调用,与servlet方法数量相同
// 名字最好不要跟dao层一样
// dao:select
// service:query
// 实现类
// 1.全局调一下dao层,方便下面调用
private UserDao userDao = new UserDaoImpl;
// 2.自由发挥

1.5servlet包

Servlet(Server Applet)是Java Servlet的简称,是为小服务程序或服务连接器,用Java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容。

// 1.注解,
@WebServlet("/user")

// 2.继承HttpServlet
public class UserServlet extends HttpServlet{}

// 3.创建服务类对象
private UserService userService = new UserServiceImpl();

// 4.重写doGet()方法,如果调用它就会调用doPost()方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    doPost(req, resp);
}

// 5.重写doPost()方法
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 首局一定要写这句,把用户传来的数据如果有汉字转为汉字,不然乱码
    req.setCharacterEncoding("utf8");
    // 这里我前端页面隐藏了一个表单,区分页面传入的是哪个方法
    // <input type="hidden" name="method" value="pn-prid">
    String method = req.getParameter("method");
    // 根据method判断需要调用什么方法
}

// 6.具体方法,举一个例子
public void queryAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 前端传来的参数
    String proCode = req.getParameter("queryProCode");
    String proName = req.getParameter("queryProName");
    Object current = req.getParameter("current");
    // 实现分页(当时划分不清楚,这块感觉可以写进service进行封装)
    int temp1 = 0;
    if (current != null) {
        temp1 = Integer.parseInt(req.getParameter("current"));
    }
    long temp = ps.queryCount(proCode,proName);
    int totalRows = (int) temp;
    Pagination<Provider> pg = new Pagination<>(temp1, totalRows, 10);
    pg.init();
    List<Provider> providers = ps.queryLimit(proCode,proName,pg.getStartRecord(), 10);
    pg.setList(providers);

	// 携带数据请求转发
    RequestDispatcher rd = req.getRequestDispatcher("WEB-INF/jsp/providerlist.jsp");
    // 携带数据
    req.setAttribute("p1",proCode);
    req.setAttribute("p2",proName);
    req.setAttribute("providers", pg.getList());
    req.setAttribute("pg", pg);
    rd.forward(req, resp);
}

2.src\main\resources

druid.properties

# 如果mysql是5版本的去掉cj
driverClassName=com.mysql.cj.jdbc.Driver
# 端口号默认3306如果修改了记得把此处进行修改
# 记得修改数据库的名字
url=jdbc:mysql://localhost:3306/数据库名字?rewriteBatchedStatements=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
# 数据库账号,根据实际填写
username=root
# 数据库密码,根据实际填写
password=quanyu9988.gmail.com
# 一般不需要更改,初始化数据库连接池
initialSize=10
# 一般不需要更改,连接池的最大数据库连接数
maxActive=20
# 一般不需要更改,超时等待时间一毫秒为单位
maxWait=1000
# 一般不需要更改,连接池的最小空闲连接数,如果空闲的连接数大于该值,则关闭多余连接,反之创建更多连接满足最小连接数的要求
minIdle=5

3.src\main\webapp

3.1WEB-INF\lib

在这里插入图片描述

在这里插入图片描述

// 不导入,连接池用不了
druid-1.1.22.jar

// 导入可以使用QueryRunner类+ResultSetHandler类,更方便的完成curd
commons-dbutils-1.7.jar

// 数据库驱动,我这里用的8
mysql-connector-java-8.0.25.jar

//使用JSTL核心标签库,需要导入下面两个依赖
standard.jar
jstl.jar

3.2WEB-INF\jsp

存放无法直接在地址栏访问的界面

3.3WEB-INF\web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--欢迎页,也就是一启动就能看见的页面-->
    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list>
</web-app>

3.4暴露在外面的内容

例如:
css
js
images

以及能直接在地址栏访问的界面
login.jsp
register.jsp

下面jsp页面第八行必须写上,才能证明他是jsp页面

<%--
    Created by IntelliJ IDEA.
    User: Qy
        Date: 2024/1/18
            Time: 20:42
                To change this template use File | Settings | File Templates.
                --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--如果用到了核心标签记得加上核心标签库--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
    <head>
        <title>Title</title>
        <%--所有外面的静态资源一定要用<%=request.getContextPath()%>代替..不然找不到数据--%>
        <link type="text/css" rel="stylesheet" href="<%=request.getContextPath()%>/css/style.css"/>
    </head>
    <body>

    </body>
</html>

4.pom.xml

这份说明没用到maven,采取自己导入jar包,这么的代码没有修改只是作为说明

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <!--    maven的基本信息-->
    <modelVersion>4.0.0</modelVersion>
    <!--    声明遵循哪一个pom模型版本-->
    <!--    组织表示,一般是公司网站倒过来-->
    <groupId>com.einmeer</groupId>
    <!--    本项目的唯一标识ID,项目名称-->
    <artifactId>qianyu</artifactId>
    <!--    项目当前版本号-->
    <version>1.0-SNAPSHOT</version>
    <!--    右边maven名字-->
    <name>qianyu</name>
    <!--    打包方式-->
    <packaging>war</packaging>
    <!--    POM之间的关系-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <junit.version>5.9.2</junit.version>
    </properties>
    <!--    依赖关系列表-->
    <dependencies>

        <!--        自己添加的lombok可以让我们在写实体类的时候大大减少代码量-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
        </dependency>


        <dependency>
            <!--            依赖项的组织名-->
            <groupId>javax.servlet</groupId>
            <!--            依赖项的子项目名-->
            <artifactId>javax.servlet-api</artifactId>
            <!--            依赖项的版本-->
            <version>4.0.1</version>
            <!--            依赖项的适用范围-->
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!--    构建设置-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.2</version>
            </plugin>
        </plugins>
    </build>
</project>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springboot中一些注解

springboot中一些注解 1:项目启动时会去扫描启动的注解&#xff0c;一般是启动时就想要被加载的方法&#xff1a; 2:springBoot中MSApplication启动类的一些其他注解&#xff1a; EnableAsync&#xff1a;这是一个Spring框架的注解&#xff0c;它用于开启方法异步调用的功能。当…

【MySQL自身的性能优化】InnoDB 的 Buffer Pool

这里写目录标题 一、引入缓存的重要性二、InnoDB 的 Buffer Pool1. Buffer Pool 内部组成2. free 链表管理空闲页3. flush 链表管理脏页4. LRU 链表提高缓存命中那咱需要咋地解决预读问题呢&#xff1f;那咱需要咋地解决 Buffer Pool 污染问题呢&#xff1f; 5. 脏页什么时候被…

pyqt5+python子域名扫描程序

import sysfrom PyQt5 import uic from PyQt5.QtWidgets import * #requests库内置了不同的方法来发送不同类型的http请求 import requests#BS主要功能是从网页抓取数据&#xff0c;提供一些简单的、python 式的函数用来处理导航、搜索、修改分析树等功能 from bs4 import Beau…

WebSocket协议、与HTTP对比

WebSocket 也可前往本人的个人网站进行阅读 WebSocket 和 HTTP WebSocket和HTTP协议一样&#xff0c;都是基于TCP协议实现的应用层协议。 HTTP协议通常是单边通信&#xff0c;主要用于传输静态文档、请求-响应通信&#xff0c;适用于Web浏览器加载网页、API调用等。然而Web…

NX二次开发获取圆弧的四个象限点

我是用来用来画水路线框的UF_MODL_ask_curve_points&#xff08;&#xff09;可以按弧长或者弧度获取曲线的等分点&#xff0c;取PI/2的圆弧&#xff0c;即将圆弧四等分&#xff0c;你也可以取任意等分点。 int GetArcPoint(tag_t arc_tag,double point[4][3]) {if(arc_tag0)r…

KubeSphere 核心实战之二【在kubesphere平台上部署redis】(实操篇 2/4)

文章目录 1、登录kubesphere平台2、redis部署分析3、redis容器启动代码4、kubesphere平台部署redis4.1、创建redis配置集4.2、创建redis工作负载4.3、创建redis服务 5、测试连接redis 在kubesphere平台上部署redis应用都是基于redis镜像进行部署的&#xff0c;所以所有的部署操…

DRmare Music Converter - 一款高效的音乐转换工具,让您的音乐无处不在!

DRmare Music Converter是一款专业的音乐转换工具&#xff0c;旨在帮助用户更方便地管理和享受音乐。无论您是使用Mac还是Windows操作系统&#xff0c;DRmare Music Converter都能为您提供高效、便捷的音乐转换体验。 DRmare Music Converter支持多种音频格式的转换&#xff0…

伊恩·斯图尔特《改变世界的17个方程》波动方程笔记

主要是课堂的补充&#xff08;yysy&#xff0c;我觉得课堂的教育模式真有够无聊的&#xff0c;PPT、写作业、考试&#xff0c;感受不到知识的魅力。 它告诉我们什么&#xff1f; 小提琴琴弦上某个小段的加速度&#xff0c;与相邻段相对于该段的平均位移成正比。 为什么重要&…

Studio One2024免费版下载及入门教程分享

众所周知&#xff0c;Studio One是一个专业的音频编辑软件&#xff0c;近几年随着音视频剪辑越来越火&#xff0c;Studio One也逐渐被人们所熟知。最近&#xff0c;就有许多小伙伴私信我&#xff0c;寻求Studio One的入门教程。 这不&#xff0c;今天小编就给大家带来了音频剪…

一个好用的工具,对网工来说是绝杀技!

上午好&#xff0c;我是老杨。 提到用人&#xff0c;很多单位和管理者第一反应都是应聘者的能力。能力到底怎么界定&#xff0c;其实每个人都有不同的判定标准。 在我看来&#xff0c;做事专注&#xff0c;且能尽可能“偷懒”的网工 &#xff0c;就是我个人筛选员工的标准。 …

Python seaborn库的边框设置(Seaborn篇-02)

Python seaborn库的边框设置(Seaborn篇-02)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔…

区间预测 | Matlab实现BiLSTM-Adaboost-ABKDE的集成双向长短期记忆网络自适应带宽核密度估计多变量回归区间预测

区间预测 | Matlab实现BiLSTM-Adaboost-ABKDE的集成双向长短期记忆网络自适应带宽核密度估计多变量回归区间预测 目录 区间预测 | Matlab实现BiLSTM-Adaboost-ABKDE的集成双向长短期记忆网络自适应带宽核密度估计多变量回归区间预测效果一览基本介绍程序设计参考资料 效果一览 …

RT-Thread Studio学习(十七)虚拟串口

RT-Thread Studio学习&#xff08;十七&#xff09;虚拟串口 一、简介二、新建RT-Thread项目并使用外部时钟三、启用USB设备功能四、测试 一、简介 本文将基于STM32F407VET芯片介绍如何在RT-Thread Studio开发环境下实现USB虚拟串口。 硬件及开发环境如下&#xff1a; OS WI…

AI学习(2): PyTorch2.x环境安装

1.介绍 注:下面是对PyTorch进行了简单的介绍&#xff0c;不喜欢可直接跳过。 1.1 什么是PyTorch PyTorch是一个由Facebook人工智能研究团队开发的开源机器学习库&#xff0c;用于开发人工智能和深度学习的应用程序。PyTorch支持广泛的机器学习和深度学习算法&#xff0c;并基于…

Flink Kubernetes Operator 介绍

一、简介 Flink Kubernetes Operator是针对在Kubernetes上运行Apache Flink应用程序而设计的工具。它充分利用了Kubernetes的优势&#xff0c;实现了对Flink集群的弹性管理和自动化操作&#xff0c;通过扩展Kubernetes API的方式&#xff0c;提供了管理和操作Flink部署的功能。…

探索设计模式的魅力:一篇文章让你彻底搞懂建造者模式

建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;旨在将一个复杂对象的创建过程与其表示分离&#xff0c;使得同样的构建过程可以创建不同的表示形式。 主要角色&#xff1a; 产品&#xff08;Product&#xff09;&#xff1a;表示正在构建…

git提权

实验环境——vulnhub-dc2靶场 git提权 前提&#xff1a;用户可以使用sudo中git权限 查看sudo权限 sudo -l可以发现git命令存在sudo提权 基于此进行权限提升 方式&#xff1a; sudo git help config #在末行命令模式输入 !/bin/bash 或 !sh #完成提权 sudo git -p help…

海外问卷调查怎么做?

大家好&#xff0c;我是橙河老师&#xff0c;我自己做海外问卷项目已经2年时间了&#xff0c;一般来说互联网项目的生命周期都不会太长&#xff0c;但海外问卷项目是一个稳定长期可做的项目&#xff0c;只要消费市场一直存在&#xff0c;问卷调查的需求就不会消失&#xff0c;我…

DBA技术栈MongoDB:简介

1.1 什么是MongoDB&#xff1f; MongoDB是一个可扩展、开源、表结构自由、用C语言编写且面向文档的数据库&#xff0c;旨在为Web应用程序提供高性能、高可用性且易扩展的数据存储解决方案。 MongoDB是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当…

深度学习记录--偏差/方差(bias/variance)

误差问题 拟合神经网络函数过程中会出现两种误差&#xff1a;偏差(bias)和方差(variance) 偏差和误差的区别 欠拟合(underfitting) 当偏差(bias)过大时&#xff0c;如左图&#xff0c;拟合图像存在部分不符合值&#xff0c;称为欠拟合(underfitting) 过拟合(overfitting) …