目录
- 1 引言
- 2 手工构建
- 3 基于Maven的构建
- 4 总结
1 引言
最近在阅读一本Java Web的书籍1时,手工实现书上的一个含多个Packages的例子,手工进行编译、运行,最终实现了效果。但感觉到整个构建过程非常繁琐,不仅要手写各个源文件的编译命令,还要考虑源文件之间的编译先后顺序;同时还要手工下载本项目所依赖的第三方Jar包。考虑到Maven具有自动化构建、依赖管理的功能,当然考虑到基于Maven重新构建和管理本项目。通过Maven工具重新构建此项目,前后对比之强烈,能让人充分感受到Maven在自动化构建、依赖管理方面的便利性,能让程序员从项目构建中解放出来,更加聚焦于业务的实现。
通过阅读本文,Maven的初学者更能深刻理解Maven存在的必要性及其应用场景;同时,对于那些只会手工编译项目的Java程序员来说,给出了切换到Maven的理由。
接下来,先叙述手工构建项目的详细过程,再叙述基于Maven构建同一项目的详细过程,最后给出二种构建方式的对比。本文所用的环境如下:
名称 | 版本 |
---|---|
Java | 1.8.0_281 |
MySQL | 8.0.13 |
Maven | 3.8.8 |
2 手工构建
下面给出一个完整的例子,其划分为6个package,每个package中都放有相关的代码。该例子还需访问MySQL数据库。由此,本例子是一个相对大型的、简单的例子,以能凸显手工编译的不便。
- 在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)
- 手工建立文件夹结构。创建一个根目录testDAO,再在其中创建三个子文件夹,如下:
- 在lib文件夹中放入本项目需要引用的第三方包mysql-connector-java-8.0.13.jar。
- 在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();
}
}
}
- 编译。要注意不同源文件的编译次序,如果次序不对,会报错。按如下编译脚本:
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
- 运行。运行也是在根目录下运行,如下脚本:
java -classpath lib/mysql-connector-java-8.0.13.jar;classes;. com/rob/test/TestInsertProduct
运行成功截图如下:
在查看数据库表中的内容是否更新:
上面是该例子的完整的手工构建过程。可以看出,其中的繁琐点在于编写编译、运行脚本。
3 基于Maven的构建
建议在运行Maven前将镜像设置为国内,我设置的是华为云的镜像。这些提供镜像的企业为广大的软件开发者提供了帮助,做了公益。
- 切换到一个新的文件夹,在命令行中输入:
mvn archetype:generate
,进入对话式创建项目骨架(项目的文件夹结构)过程,截图如下:
从上图中可以看出,Maven提供了3514种archetype供用户使用。这里,我们使用编号为2209的骨架,版本选择为1.5,然后再依次输入项目的groupId、artifactId、version等。 - 切换到根目录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();
}
}
}
- 更改项目的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>
- 在cmd console下,将当前目录切换到根目录helloworld,然后执行命令
mvn clean compile
,如下图:
- 运行指令
mvn exec:java -Dexec.mainClass="com.example.helloworld.test.TestInsertProduct"
执行主代码,如下图,
上面出现了警告信息,不用管它。 - 查看数据库内容是否更新。如下图:
至此,同一项目的基于Maven的构建讲解完毕。可以清晰地感受到,Maven帮助我们自动下载依赖的包mysql-connector-java-8.0.13.jar;所用的命令较短的情况下,创建了项目骨架、编译和运行,与手工构建形成了鲜明的对比。
4 总结
通过一个相对大型而又简单的例子阐明了手工构建和基于Maven构建的详细过程,经过实操,能感受到如下的对比结论:
- 手工构建繁琐、麻烦;基于Maven的构建方便、简单。
注意,对于Java初学者,如果正在学习某本Java书,书中的例子简单,没有划分多个包,只是1到2个源代码文件,则完全可以继续用手工的方式构建。Maven只是针对大型项目来用的,即项目代码划分为多个包,代码量比较大。
通过本文的基于Maven的构建,能帮助我们透彻理解Maven(不基于任何IDE)的构建过程,为我们后续使用集成Maven的IDE提供底层的理解细节,也能更加深刻地理解Maven在软件开发中的地位和作用,即自动化构建、依赖管理等,从而大大提高我们的工作效率。
刘鑫. JSP从零开始学: 视频教学版. 北京: 清华大学出版社, 2016. 244:252. ↩︎