通过一个含多个包且引用外部jar包的项目实例感受Maven的便利性

目录

  • 1 引言
  • 2 手工构建
  • 3 基于Maven的构建
  • 4 总结

1 引言

最近在阅读一本Java Web的书籍1时,手工实现书上的一个含多个Packages的例子,手工进行编译、运行,最终实现了效果。但感觉到整个构建过程非常繁琐,不仅要手写各个源文件的编译命令,还要考虑源文件之间的编译先后顺序;同时还要手工下载本项目所依赖的第三方Jar包。考虑到Maven具有自动化构建、依赖管理的功能,当然考虑到基于Maven重新构建和管理本项目。通过Maven工具重新构建此项目,前后对比之强烈,能让人充分感受到Maven在自动化构建、依赖管理方面的便利性,能让程序员从项目构建中解放出来,更加聚焦于业务的实现。

通过阅读本文,Maven的初学者更能深刻理解Maven存在的必要性及其应用场景;同时,对于那些只会手工编译项目的Java程序员来说,给出了切换到Maven的理由。

接下来,先叙述手工构建项目的详细过程,再叙述基于Maven构建同一项目的详细过程,最后给出二种构建方式的对比。本文所用的环境如下:

名称版本
Java1.8.0_281
MySQL8.0.13
Maven3.8.8

2 手工构建

下面给出一个完整的例子,其划分为6个package,每个package中都放有相关的代码。该例子还需访问MySQL数据库。由此,本例子是一个相对大型的、简单的例子,以能凸显手工编译的不便。

  1. 在MySQL中创建数据库、然后创建表:如下:
mysql> create database testweb;
mysql> use testweb;
mysql> CREATE TABLE product(
    -> product_id varchar(20) NOT NULL,
    -> product_name varchar(50) DEFAULT NULL,
    -> price decimal(6,2) DEFAULT NULL,
    -> info varchar(100) DEFAULT NULL,
    -> PRIMARY KEY (product_id)
    -> )ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected, 1 warning (0.84 sec)
  1. 手工建立文件夹结构。创建一个根目录testDAO,再在其中创建三个子文件夹,如下:
    文件夹结构
  2. 在lib文件夹中放入本项目需要引用的第三方包mysql-connector-java-8.0.13.jar
  3. 在src文件夹中放入如下代码(注意代码所在的packages):

Product.java:

package com.rob.pojo;

import java.io.Serializable;

public class Product implements Serializable {
    private static final long serialVersionUID = 1L;
    private String product_id;
    private String product_name;
    private double price;
    private String info;
    
    public Product(){
        super();
    }
    
    public String getProduct_id(){
        return product_id;
    }
    public void setProduct_id(String product_id){
        this.product_id = product_id;
    }
    
    public String getProduct_name(){
        return product_name;
    }
    public void setProduct_name(String product_name){
        this.product_name = product_name;
    }
    
    public double getPrice(){
        return price;
    }
    public void setPrice(double price){
        this.price = price;
    }
    
    public String getInfo(){
        return info;
    }
    public void setInfo(String info){
        this.info = info;
    }
}

DBConnection.java:

package com.rob.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBConnection {
    private static final String Driver = "com.mysql.cj.jdbc.Driver";
    private static final String URL = "jdbc:mysql://localhost:3306/testweb?serverTimezone=Asia/Shanghai&useSSL=false";
    private static final String USER = "root";
    private static final String PASSWORD = "123456";
    private Connection conn = null;
    
    public DBConnection() throws Exception {
        try {
            Class.forName(Driver);
            this.conn = DriverManager.getConnection(URL, USER, PASSWORD);
        } catch(Exception e) {
            throw e;
        }
    }
    
    public Connection getConnection(){
        return this.conn;
    }
    public void close() throws Exception {
        if (this.conn != null){
            try {
                this.conn.close();
            } catch (Exception e) {
                throw e;
            }
        }
    }
    
    // unit test 
    public static void main(String[] args) throws Exception {
        DBConnection dbconn = new DBConnection();
        System.out.println("连接成功");
        try {
            dbconn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
    }
}

ProductDao.java:

package com.rob.dao;

import java.util.List;
import com.rob.pojo.Product;

public interface ProductDao {
    /**
    * 数据库 新增数据
    *@param product 要增加的数据对象;
    *@return 是否增加成功的标记
    *@throws Exception 如果有异常,直接抛出
    */
    public boolean addProduct(Product product) throws Exception ;
    
    /**
    * 查询全部的Product数据
    *@param product_name 产品名称
    *@return 返回全部的查询结果,每一个product对象表示表的一行记录
    *@throws Exception 如果有异常,直接抛出
    */
    public List<Product> findAll(String product_name) throws Exception;
    /**
    * 根据产品编号查询产品
    *@param product_id 产品编号
    *@return 产品的vo对象
    *@throws Exception 如果有异常,直接抛出
    */
    public Product findByProductId(String product_id) throws Exception;
}

ProductDaoImpl.java:

package com.rob.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import com.rob.pojo.Product;

public class ProductDaoImpl implements ProductDao {
    private Connection conn = null;
    private PreparedStatement pstmt = null; // 数据库操作对象
    public ProductDaoImpl(Connection conn) {
        this.conn = conn;
    }
    
    public boolean addProduct(Product product) throws Exception {
        boolean flag = false;
        String sql = "insert into product(product_id, product_name, price, info) values(?,?,?,?)";
        this.pstmt = this.conn.prepareStatement(sql); //实例化PrepareStatement对象
        this.pstmt.setString(1,product.getProduct_id());
        this.pstmt.setString(2,product.getProduct_name());
        this.pstmt.setDouble(3,product.getPrice());
        this.pstmt.setString(4,product.getInfo());
        
        if (this.pstmt.executeUpdate() > 0) {
            flag = true;
        }
        this.pstmt.close();
        return flag;
    }
    
    public List<Product> findAll(String product_name) throws Exception {
        List<Product> list = new ArrayList<Product>();
        String sql = "select product_id, product_name, price, info from product";
        if (product_name != null && !"".equals(product_name)) {
            sql = "select product_id, product_name, price, info from product where product_name like?";
            this.pstmt = this.conn.prepareStatement(sql);
            this.pstmt.setString(1, "%" + product_name + "%");
        }else {
            this.pstmt = this.conn.prepareStatement(sql);
        }
        
        ResultSet rs = this.pstmt.executeQuery(); 
        Product product = null;
        while (rs.next()){
            product = new Product();
            product.setProduct_id(rs.getString(1));
            product.setProduct_name(rs.getString(2));
            product.setPrice(rs.getDouble(3));
            product.setInfo(rs.getString(4));
            list.add(product);
        }
        this.pstmt.close();
        return list;
    }
    
    public Product findByProductId(String product_id) throws Exception {
        Product product = null;
        String sql = "select product_id, product_name, price, info from product where product_id=?";
        this.pstmt = this.conn.prepareStatement(sql);
        this.pstmt.setString(1, product_id);
        ResultSet rs = this.pstmt.executeQuery();
        if(rs.next()){
            product = new Product();
            product.setProduct_id(rs.getString(1));
            product.setProduct_name(rs.getString(2));
            product.setPrice(rs.getDouble(3));
            product.setInfo(rs.getString(4));
        }
        this.pstmt.close();
        return product;
    }
}

ProductService.java:

package com.rob.service;

import java.util.List;

import com.rob.dao.ProductDao;
import com.rob.dao.ProductDaoImpl;
import com.rob.db.DBConnection;
import com.rob.pojo.Product;

public class ProductService implements ProductDao {
    private DBConnection dbconn = null;
    private ProductDao dao = null;
    
    public ProductService() throws Exception {
        this.dbconn = new DBConnection();
        this.dao = new ProductDaoImpl(this.dbconn.getConnection());
    }
    
    public boolean addProduct(Product product) throws Exception {
        boolean flag = false;
        try {
            if(this.dao.findByProductId(product.getProduct_id()) == null) {
                flag = this.dao.addProduct(product);
            }
        } catch (Exception e){
            throw e;
        } finally {
            this.dbconn.close();
        }
        return flag;
    }
    
    public List<Product> findAll(String keyWord) throws Exception {
        List<Product> all = null;
        try {
            all = this.dao.findAll(keyWord);
        } catch( Exception e) {
            throw e;
        }finally {
            this.dbconn.close();
        }
        return all;
    }
    
    public Product findByProductId(String product_id) throws Exception {
        Product product = null;
        try {
            product = this.dao.findByProductId(product_id);
        } catch (Exception e){
            throw e;
        } finally {
            this.dbconn.close();
        }
        return product;
    }
}

DAOFactory.java:

package com.rob.factory;

import com.rob.dao.ProductDao;
import com.rob.service.ProductService;

public class DAOFactory {
    public static ProductDao getIEmpDAOInstance() throws Exception {
        return new ProductService();
    }
}

最后是整个项目的主代码:TestInsertProduct.java:

package com.rob.test;

import com.rob.factory.DAOFactory;
import com.rob.pojo.Product;

public class TestInsertProduct {
    public static void main(String[] args){
        Product product = null;
        try{
            for(int i=0; i<5; i++){
                product = new Product();
                product.setProduct_id("350115001010"+i);
                product.setProduct_name("水杯"+i);
                product.setPrice(100+i);
                product.setInfo("这是一个精美的杯子"+i);
                DAOFactory.getIEmpDAOInstance().addProduct(product);
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}
  1. 编译。要注意不同源文件的编译次序,如果次序不对,会报错。按如下编译脚本:
javac -encoding utf-8 -d classes src\com\rob\pojo\Product.java
javac -classpath lib\mysql-connector-java-8.0.13.jar -d classes src\com\rob\db\DBConnection.java
javac -encoding utf-8 -classpath lib\mysql-connector-java-8.0.13.jar;classes;. -d classes src\com\rob\dao\ProductDao.java
javac -encoding utf-8 -classpath lib\mysql-connector-java-8.0.13.jar;classes;. -d classes src\com\rob\dao\ProductDaoImpl.java
javac -encoding utf-8 -classpath lib\mysql-connector-java-8.0.13.jar;classes;. -d classes src\com\rob\service\productService.java
javac -encoding utf-8 -classpath lib\mysql-connector-java-8.0.13.jar;classes;. -d classes src\com\rob\factory\DAOFactory.java
javac -encoding utf-8 -classpath lib\mysql-connector-java-8.0.13.jar;classes;. -d classes src\com\rob\test\TestInsertProduct.java
  1. 运行。运行也是在根目录下运行,如下脚本:
java  -classpath lib/mysql-connector-java-8.0.13.jar;classes;. com/rob/test/TestInsertProduct

运行成功截图如下:
运行成功截图
在查看数据库表中的内容是否更新:
查询数据库中表的内容
上面是该例子的完整的手工构建过程。可以看出,其中的繁琐点在于编写编译、运行脚本。

3 基于Maven的构建

建议在运行Maven前将镜像设置为国内,我设置的是华为云的镜像。这些提供镜像的企业为广大的软件开发者提供了帮助,做了公益。

  1. 切换到一个新的文件夹,在命令行中输入:mvn archetype:generate,进入对话式创建项目骨架(项目的文件夹结构)过程,截图如下:
    在这里插入图片描述
    在这里插入图片描述
    从上图中可以看出,Maven提供了3514种archetype供用户使用。这里,我们使用编号为2209的骨架,版本选择为1.5,然后再依次输入项目的groupId、artifactId、version等。
  2. 切换到根目录helloworld下,将前面的代码拷贝到src\main\java\com\example\helloworld下,如下图:
    在这里插入图片描述
    注意,由于包名改变,要更改每个源代码的包名位置。此外,对主程序TestInsertProduct.java,也要少许改动,以对数据库中表的更新内容区分,如下:
package com.example.helloworld.test;

import com.example.helloworld.factory.DAOFactory;
import com.example.helloworld.pojo.Product;

public class TestInsertProduct {
    public static void main(String[] args){
        Product product = null;
        try{
            for(int i=0; i<5; i++){
                product = new Product();
                product.setProduct_id("350115001010"+i+5);
                product.setProduct_name("水杯"+i+5);
                product.setPrice(100+i+5);
                product.setInfo("这是一个精美的杯子"+i+5);
                DAOFactory.getIEmpDAOInstance().addProduct(product);
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}
  1. 更改项目的pom.xml文件。改动部分如下:
 <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.release>1.8</maven.compiler.release>
  </properties>
  <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.13</version>
  </dependency>
  1. 在cmd console下,将当前目录切换到根目录helloworld,然后执行命令mvn clean compile,如下图:
    在这里插入图片描述
  2. 运行指令mvn exec:java -Dexec.mainClass="com.example.helloworld.test.TestInsertProduct"执行主代码,如下图,
    在这里插入图片描述
    上面出现了警告信息,不用管它。
  3. 查看数据库内容是否更新。如下图:
    在这里插入图片描述
    至此,同一项目的基于Maven的构建讲解完毕。可以清晰地感受到,Maven帮助我们自动下载依赖的包mysql-connector-java-8.0.13.jar;所用的命令较短的情况下,创建了项目骨架、编译和运行,与手工构建形成了鲜明的对比。

4 总结

通过一个相对大型而又简单的例子阐明了手工构建和基于Maven构建的详细过程,经过实操,能感受到如下的对比结论:

  • 手工构建繁琐、麻烦;基于Maven的构建方便、简单。

注意,对于Java初学者,如果正在学习某本Java书,书中的例子简单,没有划分多个包,只是1到2个源代码文件,则完全可以继续用手工的方式构建。Maven只是针对大型项目来用的,即项目代码划分为多个包,代码量比较大。

通过本文的基于Maven的构建,能帮助我们透彻理解Maven(不基于任何IDE)的构建过程,为我们后续使用集成Maven的IDE提供底层的理解细节,也能更加深刻地理解Maven在软件开发中的地位和作用,即自动化构建、依赖管理等,从而大大提高我们的工作效率。


  1. 刘鑫. JSP从零开始学: 视频教学版. 北京: 清华大学出版社, 2016. 244:252. ↩︎

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

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

相关文章

el-tree拖拽光标错位问题

背景&#xff1a;el-tree实现的分类树增加拖拽功能后&#xff0c;当分类树由于数量较多产生滚动条&#xff0c;如果分类树已滚动&#xff0c;进行拖拽时会造成光标错位的问题: 原因&#xff1a;el-tree拖拽光标定位的高度并未加上滚动的高度解决&#xff1a;将滚动的样式属性放…

【YashanDB知识库】解决mybatis的mapper文件sql语句结尾加分号“;“报错

本文内容来自YashanDB官网&#xff0c;原文内容请见 https://www.yashandb.com/newsinfo/7863046.html?templateId1718516 现象 mybatis或mybaits-plus的mapper文件sql结尾加分号";" 执行时报错&#xff1a;”YAS-04209 unexpected word;“ 解决办法 将sql结尾…

day03-前端Web-Vue3.0基础

目录 前言1. Vue概述2. 快速入门2.1 需求2.2 步骤2.3 实现 3. Vue指令3.1 介绍3.2 v-for3.2.1 介绍3.2.2 演示3.2.3 v-for的key3.2.4 案例-列表渲染 3.3 v-bind3.3.1 介绍3.3.2 演示3.3.3 案例-图片展示 3.4 v-if & v-show3.4.1 介绍3.4.2 案例-性别职位展示 3.6 v-model3.…

Spring Web 嵌套对象校验失效

问题复现 当开发一个学籍管理系统时&#xff0c;我们会提供了一个 API 接口去添加学生的相关信息&#xff0c;学生中有个嵌套属性联系电话&#xff0c;其对象定义参考下面的代码&#xff1a; import lombok.Data; import javax.validation.constraints.Size; Data public class…

计算机网络 (27)IP多播

前言 IP多播&#xff08;也称多址广播或组播&#xff09;技术是一种允许一台或多台主机&#xff08;多播源&#xff09;发送单一数据包到多台主机&#xff08;一次性的、同时的&#xff09;的TCP/IP网络技术。 一、基本概念 定义&#xff1a;多播作为一点对多点的通信&#xff…

计算机毕业设计PyHive+Hadoop深圳共享单车预测系统 共享单车数据分析可视化大屏 共享单车爬虫 共享单车数据仓库 机器学习 深度学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

口碑很好的国产LDO芯片,有哪些?

在几乎任何一个电路设计中&#xff0c;都可能会使用LDO&#xff08;低压差线性稳压器&#xff09;这个器件。 虽然LDO不是什么高性能的IC&#xff0c;但LDO芯片市场竞争异常激烈。最近几年&#xff0c;诞生了越来越多的精品国产LDO&#xff0c;让人看得眼花缭乱。 业内人士曾经…

Transformer:深度学习的变革力量

深度学习领域的发展日新月异&#xff0c;在自然语言处理&#xff08;NLP&#xff09;、计算机视觉等领域取得了巨大突破。然而&#xff0c;早期的循环神经网络&#xff08;RNN&#xff09;在处理长序列时面临着梯度消失、并行计算能力不足等瓶颈。而 Transformer 的横空出世&am…

低代码从“产品驱动”向“场景驱动”转型,助力数字化平台构建

一、前言 在数字化时代的大潮中&#xff0c;从宏观层面来看&#xff0c;新技术的落地速度不断加快&#xff0c;各行各业的数字化进程呈现出如火如荼的态势。而从微观层面剖析&#xff0c;企业面临着行业格局快速变化、市场竞争日益激烈以及成本压力显著增强等诸多挑战。 据专…

01-51单片机LED与独立按键

一、单片机概述 注意&#xff1a;个人学习笔记&#xff0c;里面涉及到的C语言和进程转换相关的知识在C语言部分已经写了&#xff0c;这里是默认都会的状态学习单片机。 1.什么是单片机 单片机&#xff0c;英文Micro Controller Unit&#xff0c;简称MCU。其内部集成了CPU、R…

腾讯云AI代码助手编程挑战赛-刑说

作品简介 鉴于当代普法力度不够大&#xff0c;这个刑说可以帮助大家更好的普及法律知识 技术架构 采用了全后端分离的架构&#xff0c;前端使用Vue.js&#xff0c;腾讯云的AI服务处理自然语言理解与生成。 实现过程 开发环境、开发流程 系统&#xff1a;win11 开发工具&…

Elasticsearch:聚合操作

这里写目录标题 一、聚合的概述二、聚合的分类1、指标聚合&#xff08;Metric Aggregation&#xff09;2、桶聚合&#xff08;Bucket Aggregation&#xff09;3、管道聚合&#xff08;Pipeline Aggregation&#xff09; 三、ES聚合分析不精准原因分析四、聚合性能优化1、ES聚合…

升级 Spring Boot 3 配置讲解 —— 为何 SpringBoot3 淘汰了 JDK8?

学会这款 &#x1f525;全新设计的 Java 脚手架 &#xff0c;从此面试不再怕&#xff01; 随着 Spring Boot 3 的发布&#xff0c;许多开发者发现了一个重要的变化&#xff1a;Spring Boot 3 不再支持 JDK 8。这一变化引发了不少讨论&#xff0c;尤其是对于那些仍然在使用 JDK …

rhcsa练习(3)

1 、创建文件命令练习&#xff1a; &#xff08; 1 &#xff09; 在 / 目录下创建一个临时目录 test &#xff1b; mkdir /test &#xff08; 2 &#xff09;在临时目录 test 下创建五个文件&#xff0c;文件名分别为 passwd &#xff0c; group &#xff0c; bashrc &#x…

汽车免拆诊断 | 2007款保时捷Carrera S车行驶中发动机冷却液温度报警灯异常点亮

故障现象 一辆2007款保时捷Carrera S车&#xff0c;搭载3.8 L自然吸气发动机&#xff0c;累计行驶里程约为7.8万km。车主反映&#xff0c;车辆行驶一段距离后&#xff0c;组合仪表上的发动机冷却液温度报警灯异常点亮。为此&#xff0c;在其他维修厂已更换过节温器、发动机冷却…

ffmpeg7.0 aac转pcm

#pragma once #define __STDC_CONSTANT_MACROS #define _CRT_SECURE_NO_WARNINGSextern "C" { #include "libavcodec/avcodec.h" }//缓冲区大小&#xff08;缓存5帧数据&#xff09; #define AUDIO_INBUF_SIZE 40960 /*name depthu8 8s16 …

Clisoft SOS设置Server和Project

Clisoft SOS设置Server和Project 一、关于SOS Servers、Clients、Projects和Work Areas 以下三个图是官方文档中介绍的三种情况 图1&#xff1a;带有两个客户端的SOS服务器 图2&#xff1a;使用本地缓存服务器 图3&#xff1a;远程设计团队的缓存服务器 因为SOS软件需要…

Windows 安装 Docker 和 Docker Compose

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template &#x1f33a; 仓库主页&#xff1a; GitCode︱ Gitee ︱ Github &#x1f496; 欢迎点赞 &#x1f44d; 收藏 ⭐评论 …

深入理解plt和got表

前言 plt表和got表是和链接过程相关的表。我们知道&#xff0c;一个可执行文件的生成过程需要经过预处理&#xff0c;编译&#xff0c;汇编&#xff0c;链接四个过程。链接又分为静态链接和动态链接。静态链接是发生在程序执行之前&#xff0c;动态链接是发生在程序执行中。 …

深入学习RocketMQ

参考&#xff1a;RocketMQ从从入门到精通_rocketmq入门到精通-CSDN博客 1、消息的类型 普通消息 顺序消息 延时消息 批量消息 事务消息 2、在java中使用 2.1、pom.xml中加入依赖 <dependency><groupId>org.apache.rocketmq</groupId><artifactId…