搭建一个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 userGender = ? limit ?,?";

// 4.创建一个对象类数组(里面放?号代替的东西,注意位置不要错)
// 如果就一个参数或者不需要参数不用写这个,多个参数再写
Object[] param = {"%"+username+"%",userGender,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

image

image

// 不导入,连接池用不了
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>
posted @   芊嵛  阅读(606)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
  1. 1 イエスタデイ(翻自 Official髭男dism) 茶泡饭,春茶,kobasolo
  2. 2 世间美好与你环环相扣 柏松
世间美好与你环环相扣 - 柏松
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 尹初七

作曲 : 柏松

编曲 : 彭圣杰

偏偏秉烛夜游

偏偏秉烛夜游

午夜星辰 似奔走之友

爱你每个结痂伤口

酿成的陈年烈酒

入喉尚算可口

入喉尚算可口

怎么泪水 还偶尔失守

邀你细看心中缺口

裂缝中留存 温柔

此时已莺飞草长 爱的人正在路上

此时已莺飞草长 爱的人正在路上

我知他风雨兼程 途经日暮不赏

穿越人海 只为与你相拥

此刻已皓月当空 爱的人手捧星光

我知他乘风破浪 去了黑暗一趟

感同身受 给你救赎热望

知道你不能 还要你感受

知道你不能 还要你感受

让星光加了一点彩虹

让樱花偷偷 吻你额头

让世间美好 与你环环相扣

此时已莺飞草长 爱的人正在路上

此时已莺飞草长 爱的人正在路上

我知他风雨兼程 途经日暮不赏

穿越人海 只为与你相拥

此刻已皓月当空 爱的人手捧星光

我知他乘风破浪 去了黑暗一趟

感同身受 给你救赎热望

此时已莺飞草长 爱的人正在路上

此时已莺飞草长 爱的人正在路上

我知他风雨兼程 途经日暮不赏

穿越人海 只为与你相拥

此刻已皓月当空 爱的人手捧星光

我知他乘风破浪 去了黑暗一趟

感同身受 给你救赎热望

知道你不能 还要你感受

知道你不能 还要你感受

让星光加了一点彩虹

当樱花开的纷纷扬扬

当世间美好 与你环环相扣

特别鸣谢:槿葵,我们的海报制作妹妹。

原唱:柏松

吉他:柏松

和声:柏松

录音:柏松

混音:张强

点击右上角即可分享
微信分享提示