VIP创新项目1课程总结2021-2022学年第1学期

2022-11-12 16:00:16 浏览数 (1)

VIP创新项目1课程总结2021-2022学年第1学期

1. Java基础

1.1 Java代码是如何执行的

参考: https://zhuanlan.zhihu.com/p/92906774 Java执行过程如下图:

  1. 在指定目录下,编写Java代码,Hello.java源代码如下:
代码语言:javascript复制
class Hello{ 
public static void main(String[] agrs){ 
     System.out.println("hello"); 
	} 
}
  1. 编译java源代码 当java源程序编码结束后,就需要编译器编译。 安装好jdk后,我们打开jdk目录,有两个.exe文件,即javac.exe(编译源代码,xxx.java文件) 和 java.exe(执行字节码,xxx.class文件).

用命令行进入到该目录下,编译这个文件javac Hello.java

代码语言:javascript复制
F:你的工程所在路径>javac Hello.java
  1. 将编译后的Hello.class文件打成jar包 jar -cvf hello.jar Hello.class c表示要创建一个新的jar包,v表示创建的过程中在控制台输出创建过程的一些信息,f表示给生成的jar包命名
代码语言:javascript复制
 F:你的工程所在路径> jar -cvf hello.jar Hello.class
 已添加清单
 正在添加: Hello.class(输入 = 409) (输出 = 280)(压缩了 31%)
  1. 运行jar包 java -jar hello.jar 这时会报如下错误 hello.jar中没有主清单属性
代码语言:javascript复制
F:你的工程所在路径>java -jar hello.jar
hello.jar中没有主清单属性
  • 解决办法1: java -classpath hello.jar Hello
  • 解决办法2:添加Main-Class属性 MENIFEST.MF书写规范见: https://blog.csdn.net/shadow_zed/article/details/80393757

  1. 最后一样一定要回车,空一行,不然无法识别最后一行的配置。
  2. Manifest-Version、Main-Class和Class-Path后面跟着一个英文的冒号,冒号后面必须跟着一个空格,然后才是版本号、类和ClassPath。
  3. Class-Path中的各项应使用空格分隔,不是逗号或分号。
  4. Class-Path中如果有很多项,写成一行打包的时候会报错line too long,这时需要把Class-Path分多行写。注意:从第二行开始,必须以两个空格开头,三个以上我没试过,不过不用空格开头和一个空格开头都是不行的,我已经试过了。
  5. Class-Path写完之后最后一定要有一个空行。
  6. jar包内有些配置文件想放在jar包外面,比如文件config.properties:如果这个文件是以路径方式载入的,比如new file("./config/config.properties"),那么将config.properties放在jar包相同目录下的config目录下即可,也就是说“./”路径等价于jar包所在目录;如果这个文件是以ClassPath下的文件这种方式载入的,比如在Spring中载入classpath:config.properties,则在MF文件的配置文件的ClassPath中添加“./”,然后将这个配置文件与jar包放在同一个目录即可,当然也可以在MF文件的配置文件的ClassPath中添加“./config/”,然后把配置文件都放在jar包相同目录下的config目录下。

用压缩软件打开hello.jar,会发现里面多了一个META-INF文件夹,里面有一个MENIFEST.MF的文件,用记事本打开

代码语言:javascript复制
    Manifest-Version: 1.0
    Created-By: 1.8.0_121 (Oracle Corporation)
    Main-Class: Hello

在第三行的位置写入 Main-Class: Hello (注意冒号后面有一个空格,整个文件最后有一行空行),保存 再次运行

代码语言:javascript复制
java -jar hello.jar

此时成功在控制台看到 hello ,成功

备注: .jar分2种,有一种只是当作调用包;另外一种是可以直接执行,类似.exe。 但是一般可直接执行的*.jar文件,用winrar等解压软件打开会发现都有一个META-INF的文件夹,这个文件夹中必须有个MANIFEST.MF文件,这个文件主要是用来描述可执行的*.jar的执行入口文件(通常是含有main()方法的类文件),格式大体如下:

代码语言:javascript复制
Manifest-Version: 1.0
Created-By: 1.4.2_08 (Sun Microsystems Inc.)
Main-Class: Main

这边Main既是运行类,含有main()方法的一个类文件,名字为Main.class。

1.2Java打包案例

1.带package的jar包——直接输出hello

方法步骤

(0)创建目录F:Example_Project

(1)创建edu.hncj.vip目录,用记事本写一个Hello.java的文件

代码语言:javascript复制
package edu.hncj.vip;

class Hello{
     public static void main(String[] agrs){
         System.out.println("hello");
     }
}

(2)用命令行进入到该目录下,编译这个文件javac -d . Hello.java

代码语言:javascript复制
F:Example_Projecteduhncjvip>javac -d . Hello.java

javac -d . 中 -d参数:编译时,同时由系统自动生成package目录 .参数:指定Hello.java类的包名 将要生成在哪个目录下,.表示当前目录,可以任意指定

(3)将编译后的Hello.class文件打成jar包

代码语言:javascript复制
jar -cvf hello.jar eduhncjvip

F:Example_Projecteduhncjvip>jar -cvf hello.jar eduhncjvip
已添加清单
正在添加: edu/hncj/vip/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: edu/hncj/vip/Hello.class(输入 = 422) (输出 = 292)(压缩了 30%)

c表示要创建一个新的jar包,v表示创建的过程中在控制台输出创建过程的一些信息,f表示给生成的jar包命名

(4)运行jar包

代码语言:javascript复制
   java -jar hello.jar

这时会报如下错误 hello.jar中没有主清单属性

用压缩软件打开hello.jar,会发现里面多了一个META-INF文件夹,里面有一个MENIFEST.MF的文件,用记事本打开

添加Main-Class属性

代码语言:javascript复制
Manifest-Version: 1.0
Created-By: 1.8.0_181 (Oracle Corporation)
Main-Class: edu.hncj.vip.Hello

在第三行的位置写入 Main-Class: Hello (注意冒号后面有一个空格,整个文件最后有一行空行),保存

再次运行 java -jar hello.jar ,此时成功在控制台看到 hello ,成功

2.含有两个类的jar包——通过调用输出hello

(0)创建目录F:Example_Project两个类的jar>

(1)用记事本写一个Hello.java和一个Student.java的文件

目的是让Hello调用Student的speak方法

代码语言:javascript复制
class Hello{
     public static void main(String[] agrs){
         //System.out.println("hello");
		 Student.speak();
     }
}

class Student{
    public static void speak(){
        System.out.println("hello,I'm 20级学生 ");
    }
}

(2)编译: javac -encoding UTF-8 Hello.java

此时Hello.java和Student.java同时被编译,因为Hello中调用了Student,在编译Hello的过程中发现还需要编译Student

代码语言:javascript复制
F:Example_Project两个类的jar>javac -encoding UTF-8 Hello.java

(3)打jar包

在F:Example_Project两个类的jar>下创建META-INF文件夹

代码语言:javascript复制
F:Example_Project两个类的jar>mkdir META-INF

在META-INF下创建MANIFEST.MF

代码语言:javascript复制
F:Example_Project两个类的jar>type nul>META-INFMANIFEST.MF

这次我们换一种方式直接定义Main-Class。

代码语言:javascript复制
Manifest-Version: 1.0
Created-By: 1.8.0_121 (Oracle Corporation)
Main-Class: Hello

事先准备好上述的MANIFEST.MF文件,并存放在META-INF文件夹下,此时打jar包的命令如下

代码语言:javascript复制
F:Example_Project两个类的jar> jar -cvfm hello.jar META-INFMANIFEST.MF Hello.class Student.class
已添加清单
正在添加: Hello.class(输入 = 293) (输出 = 223)(压缩了 23%)
正在添加: Student.class(输入 = 408) (输出 = 308)(压缩了 24%)

jar -cvfm hello.jar META-INFMANIFEST.MF Hello.class Student.class命令解释如下: 表示用第一个文件当做MENIFEST.MF文件,hello.jar作为名称,将Hello.class和Student.class打成jar包。其中多了一个参数m,表示要定义MANIFEST文件

(4)运行 java -jar hello.jar ,此时成功在控制台看到 hello ,成功

代码语言:javascript复制
F:Example_Project两个类的jar> java -jar hello.jar
hello,I'm 20级学生
3.有目录结构的jar包——通过引包并调用输出hello

(0)创建文件夹

F:Example_Project有目录结构的两个类jar

(1)我们将上一个稍稍变化一下,将Student这个类放在edu.hncj.vip包下,Hello放在com包下

修改Hello.java文件

代码语言:javascript复制
package com;

import edu.hncj.vip.Student;
class Hello{
     public static void main(String[] agrs){
         //System.out.println("hello");
		 Student.speak();
     }
}

修改Student.java文件,注意需要修改为public公共类

代码语言:javascript复制
package edu.hncj.vip;

public class Student{
    public static void speak(){
        System.out.println("hello,I'm 20级学生 ");
    }
}

查看当前目录结构

代码语言:javascript复制
F:Example_Project有目录结构的两个类jar>tree .  /f  /a
卷 工作 的文件夹 PATH 列表
卷序列号为 00000057 5296:88B3
F:EXAMPLE_PROJECT有目录结构的两个类JAR
 ---com
|       Hello.java
|
---edu
    ---hncj
        ---vip
                Student.java

方法步骤

(1)编译Hello.java

代码语言:javascript复制
 javac -encoding UTF-8 -d . comHello.java

编译Hello.java时,自动编译Student.java文件

(2)打jar包,同样准备好MANIFEST文件

在F:Example_Project两个类的jar>下创建META-INF文件夹

代码语言:javascript复制
F:Example_Project有目录结构的两个类jar>mkdir META-INF

在META-INF下创建MANIFEST.MF

代码语言:javascript复制
F:Example_Project有目录结构的两个类jar>type nul>META-INFMANIFEST.MF

这次我们换一种方式直接定义Main-Class。注意后面的空行

代码语言:javascript复制
Manifest-Version: 1.0
Created-By: 1.8.0_121 (Oracle Corporation)
Main-Class: com.Hello
此处有空行

事先准备好上述的MANIFEST.MF文件,并存放在META-INF文件夹下,此时打jar包的命令如下

代码语言:javascript复制
jar -cvfm hello.jar META-INFMANIFEST.MF comHello.class eduhncjvip

F:Example_Project有目录结构的两个类jar>jar -cvfm hello.jar META-INFMENIFEST.MF comHello.class eduhncjvip
已添加清单
正在添加: com/Hello.class(输入 = 310) (输出 = 238)(压缩了 23%)
正在添加: edu/hncj/vip/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: edu/hncj/vip/Student.class(输入 = 421) (输出 = 319)(压缩了 24%)
正在添加: edu/hncj/vip/Student.java(输入 = 146) (输出 = 130)(压缩了 10%)

输出信息表示已经把哪些文件打包在hello.jar中

(3)运行 java -jar hello.jar ,此时成功在控制台看到 hello ,成功

4.制作含有jar文件的jar包

我们将场景稍稍变得复杂一点,看看jar包中需要引入其他jar包的场景

1、两个jar包间相互调用——调用jar外的jar输出hello

最终生成的jar包结构

hello.jar tom.jar

方法步骤

(0)生成student.jar

准备:创建Student.java文件

代码语言:javascript复制
public class Student{
    public static void speak(){
        System.out.println("hello,I'm 20级学生 ");
    }
}

在Student.java同级目录下打开cmd 执行如下命令编译java文件

代码语言:javascript复制
javac -encoding UTF-8 Student.java 

执行jar -cvf student.jar Student.class 命令生成jar包

代码语言:javascript复制
F:Example_Project两个jar相互调 用>javac -encoding UTF-8 Student.java

F:Example_Project两个jar相互调 用>jar -cvf student.jar Student.class
已添加清单
正在添加: Student.class(输入 = 408) (输出 = 307)(压缩了 24%)

(1)编写一个Hello.java并将其编译成Hello.class,注意,由于Hello里面引用了Student类的speak方法,因此在打jar包时应使用-cp参数,将student.jar包引入

Hello.java文件内容:

代码语言:javascript复制
class Hello{
     public static void main(String[] agrs){
         //System.out.println("hello");
		 Student.speak();
     }
}

执行 javac命令编译Hello.java 如果直接编译Hello.java会提示如下错误

代码语言:javascript复制
F:Example_Project两个jar相互调用>javac  Hello.java
Hello.java:5: 错误: 找不到符号
                Student.speak();
                ^
符号:   变量 Student
位置: 类 Hello
 1 个错误

可以在编译Hello.java的同时,把依赖的jar放在classpath下

代码语言:javascript复制
 F:Example_Project两个jar相互调 用>javac -cp student.jar Hello.java

这里的 -cp 表示 -classpath,指的是把student.jar加入classpath路径下

(2)将hello.class达成jar包

创建META-INF目录,创建MANIFEST.MF 文件,注意末尾的空行

代码语言:javascript复制
Manifest-Version: 1.0
Created-By: 1.8.0_181 (Oracle Corporation)
Main-Class: Hello
这里有空行

达成jar包,执行jar -cvfm hello.jar META-INF/MANIFEST.MF hello.class

代码语言:javascript复制
F:Example_Project两个jar相互调 用>jar -cvfm hello.jar META-INF/MANIFEST.MF Hello.class
已添加清单
正在添加: Hello.class(输入 = 293) (输出 = 223)(压缩了 23%)

目前可以顺利的达成jar包,但运行时会出错,如下。 (3)此时运行 java -jar 发现报错 ClassNotFoundException:Student

代码语言:javascript复制
F:Example_Project两个jar相互调 用>java -jar hello.jar
Exception in thread "main" java.lang.NoClassDefFoundError: Student
        at Hello.main(Hello.java:5)
Caused by: java.lang.ClassNotFoundException: Student
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 1 more

原因很简单,引入jar包需要在MENIFEST.MF文件中配置一个新属性:Class-Path,路径指向你需要的所有jar包

现在打开hello.jar中MENIFEST.MF文件,添加Class-Path。应该变成

代码语言:javascript复制
Manifest-Version: 1.0
Created-By: 1.8.0_121 (Oracle Corporation)
Main-Class: Hello
Class-Path: student.jar

(4)好了,修改这个文件,再次运行,发现成功在控制台输出 hello

tips:引入多个jar包,中间用空格隔开

至此,我们可以总结出,命令变化如下

javac -cp xxx.jar 要编译的文件 -d 目标位置

jar -cvfm 命名 MENIFEST文件 要打包的文件1 要打包的文件2

5.jar包中含有jar包——调用jar内的jar输出hello

当项目中我们把所需要的第三方jar包也打进了我们自己的jar包中时,如果仍然按照上述操作方式,会报找不到Class异常。原因就是jar引用不到放在自己内部的jar包。 这种情况的具体实现细节比较复杂,可以先参考这篇文章:

http://www.cnblogs.com/adolfmc/archive/2012/10/07/2713562.html

引用方法1:使用AppClassloader来加载

引用方法2:也可以把需要加载的jar都扔到%JRE_HOME%/lib/ext下面,这个目录下的jar包会在Bootstrap Classloader工作完后由Extension Classloader来加载。非常方便,非常省心。

(1)本部分使用AppClassloader加载

在F:Example_Projectjar包内含有jar包 的目录下创建edu.hncj.vip.Student.java

代码语言:javascript复制
package edu.hncj.vip;

public class Student{
    public static void speak(){
        System.out.println("hello,I'm 20级学生 ");
    }
}

(2)生成student.jar文件 编译Student.java文件,执行 javac -d . -encoding UTF-8 edu/hncj/vip/Student.java命令

代码语言:javascript复制
F:Example_Projectjar包内含有jar包>javac -d . -encoding UTF-8 edu/hncj/vip/Student.java

生成student.jar包,jar -cvf student.jar eduhncjvip

代码语言:javascript复制
F:Example_Projectjar包内含有jar包>jar -cvf student.jar eduhncjvip
已添加清单
正在添加: edu/hncj/vip/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: edu/hncj/vip/Student.class(输入 = 421) (输出 = 319)(压缩了 24%)
正在添加: edu/hncj/vip/Student.java(输入 = 146) (输出 = 130)(压缩了 10%)

在 F:Example_Projectjar包内含有jar包 目录下创建lib目录,把student放置在lib目录下

(3)创建Hello.java,并编译 在 F:Example_Projectjar包内含有jar包 目录下创建com.Hello.java,Hello中调用了Student

代码语言:javascript复制
package com;
import edu.hncj.vip.Student;
class Hello{
     public static void main(String[] agrs){
         //System.out.println("hello");
		 Student.speak();
     }
}

编译Hello.java文件,javac -d . -encoding UTF-8 com/Hello.java

代码语言:javascript复制
F:Example_Projectjar包内含有jar包>javac -d . -encoding UTF-8 com/Hello.java

生成hello.jar包,jar -cvf hello.jar com lib

代码语言:javascript复制
F:Example_Projectjar包内含有jar包>jar -cvf hello.jar com lib
已添加清单
正在添加: com/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: com/Hello.class(输入 = 310) (输出 = 237)(压缩了 23%)
正在添加: com/Hello.java(输入 = 175) (输出 = 138)(压缩了 21%)
正在添加: lib/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: lib/student.jar(输入 = 1179) (输出 = 790)(压缩了 32%)

(4)运行hello.jar,java -cp hello.jar com.Hello

代码语言:javascript复制
F:Example_Projectjar包内含有jar包>java -cp hello.jar com.Hello
Exception in thread "main" java.lang.NoClassDefFoundError: edu/hncj/vip/Student
        at com.Hello.main(Hello.java:6)
Caused by: java.lang.ClassNotFoundException: edu.hncj.vip.Student
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 1 more

修改hello.jar中的MANIFEST.MF文件

代码语言:javascript复制
Manifest-Version: 1.0
Created-By: 1.8.0_181 (Oracle Corporation)
Class-Path: lib/student.jar

再次运行java -cp hello.jar com.Hello即可

6.读取jar外的配置文件

(1)在F:Example_Project读取jar外的文件 目录中创建Hello.java

Hello.java文件

代码语言:javascript复制
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.FileInputStream;

class Hello{
    public static void main(String[] args) throws Exception{
        Hello hello = new Hello();
        InputStream is = new FileInputStream("jarconf.txt");
        print(is);
    }
    
    /**
     * 读取文件,输出里面的内容,通用方法
     */
    public static void print(InputStream inputStream) throws Exception {
        InputStreamReader reader = new InputStreamReader(inputStream, "utf-8");
        BufferedReader br = new BufferedReader(reader);
        String s = "";
        while ((s = br.readLine()) != null)
            System.out.println(s);
        inputStream.close();
    }
}

(2)同级目录下创建jarconf.txt文本文件,内容如下:

代码语言:javascript复制
calssname=vip
desc=这是一个外部配置文件

(3)编译并打包java文件 : 编译Hello.java文件

代码语言:javascript复制
javac -encoding UTF-8 Hello.java

打包hello.jar文件 :

代码语言:javascript复制
jar -cvf hello.jar Hello.class

修改META-INFMANIFEST.MF文件添加

代码语言:javascript复制
Manifest-Version: 1.0
Created-By: 1.8.0_181 (Oracle Corporation)
Main-Class: Hello

执行jar:java -jar hello.jar

完整代码如下:

代码语言:javascript复制
# 编译Hello.java文件为class文件
F:Example_Project读取jar内的文 件>javac -encoding UTF-8 Hello.java

# 生成jar包,
F:Example_Project读取jar外的文 件>jar -cvf hello.jar Hello.class
已添加清单
正在添加: Hello.class(输入 = 1008) (输出 = 594)(压缩了 41%)

# 修改hello.jar中的META-INFMANIFEST.MF

# 执行jar
F:Example_Project读取jar外的文 件>java -jar hello.jar
calssname=vip
desc=这是一个外部配置文件

此时的目录结构

F:Example_Project读取jar外的文 件>tree . /f /a
卷 工作 的文件夹 PATH 列表
卷序列号为 00000001 5296:88B3
F:EXAMPLE_PROJECT读取JAR外的文 件
|   Hello.class
|   hello.jar
|   Hello.java
|   jarconf.txt
|
---META-INF
        MANIFEST.MF
7.读取jar内的配置文件

(1)在F:Example_Project读取jar内的文件中创建Hello.java

Hello.java文件

代码语言:javascript复制
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;

class Hello{
    public static void main(String[] args) throws Exception{
        Hello hello = new Hello();
        InputStream is = hello.getClass().getResourceAsStream("jarconf.txt");
        print(is);
    }
    
    /**
     * 读取文件,输出里面的内容,通用方法
     */
    public static void print(InputStream inputStream) throws Exception {
        InputStreamReader reader = new InputStreamReader(inputStream, "utf-8");
        BufferedReader br = new BufferedReader(reader);
        String s = "";
        while ((s = br.readLine()) != null)
            System.out.println(s);
        inputStream.close();
    }
}

同级目录下创建jarconf.txt文本文件,内容如下:

代码语言:javascript复制
calssname=vip
desc=这是一个内部配置文件

(2)编译并打成jar包 编译java文件 :

代码语言:javascript复制
javac -encoding UTF-8 Hello.java

打包class文件 :

代码语言:javascript复制
jar -cvfm hello.jar META-INFMANIFEST.MF . 

执行jar:

代码语言:javascript复制
java -jar hello.jar

(3)完整过程如下:

代码语言:javascript复制
# 编译Hello.java文件为class文件
F:Example_Project读取jar内的文件>javac -encoding UTF-8 Hello.java

# 生成jar包,同时制定META-INFMANIFEST.MF
F:Example_Project读取jar内的文件>jar -cvfm hello.jar META-INFMANIFEST.MF .
已添加清单
正在添加: Hello.class(输入 = 1109) (输出 = 637)(压缩了 42%)
正在添加: Hello.java(输入 = 755) (输出 = 385)(压缩了 49%)
正在添加: jarconf.txt(输入 = 50) (输出 = 55)(压缩了 -10%)
正在忽略条目META-INF/
正在忽略条目META-INF/MANIFEST.MF

# 执行hello.jar
F:Example_Project读取jar内的文 件>java -jar hello.jar
calssname=vip
desc=这是一个内部配置文件

2.Maven专题

2.1Maven简介

Maven是一种构建工具(打包项目)、依赖管理工具(资源依赖管理工具:主要用于集成资源)、项目信息聚合工具。

2.2Maven安装与常用配置

(1)安装过程 最简安装:

代码语言:javascript复制
选择版本
下载解压
配置MAVEN_HOME环境变量
通过mvn -version确定下版本

这种安装没有修改setting.xml,会导致Maven下载的依赖位于C盘,并且默认从中央仓库下载,可能网速慢一些,这时可修改如下配置:

打开D:安装目录mavenconfsettings.xml文件,查找修改如下配置:

代码语言:javascript复制
<!-- 修改本地仓库位置 -->
<localRepository>d:/apache/maven/maven-repo</localRepository>

<!-- 修改镜像地址 -->
<mirrors>
<!-- 给定仓库的下载镜像。 -->
<mirror>
    <!-- 该镜像的唯一标识符。id用来区分不同的mirror元素。 -->
	<id>nexus-aliyun</id>
	<!-- 被镜像的服务器的id。例如,如果我们要设置了一个Maven中央仓库(http://repo.maven.apache.org/maven2/)的镜像,就需要将该元素设置成central。这必须和中央仓库的id central完全一致。 -->
	<mirrorOf>*,!jeecg,!jeecg-snapshots,!getui-nexus</mirrorOf>
	<!-- 镜像名称 -->
	<name>Nexus aliyun</name>
	<!-- 该镜像的URL。构建系统会优先考虑使用该URL,而非使用默认的服务器URL。 -->
	<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror> 
</mirrors>

<repositories>
  <!--包含需要连接到远程仓库的信息 -->
  <repository>
    <!--远程仓库唯一标识 -->
    <id>codehausSnapshots</id>
    <!--远程仓库名称 -->
    <name>Codehaus Snapshots</name>
    <!--如何处理远程仓库里发布版本的下载 -->
    <releases>
      <!--true或者false表示该仓库是否为下载某种类型构件(发布版,快照版)开启。 -->
      <enabled>false</enabled>
      <!--该元素指定更新发生的频率。Maven会比较本地POM和远程POM的时间戳。这里的选项是:always(一直),daily(默认,每日),interval:X(这里X是以分钟为单位的时间间隔),或者never(从不)。 -->
      <updatePolicy>always</updatePolicy>
      <!--当Maven验证构件校验文件失败时该怎么做-ignore(忽略),fail(失败),或者warn(警告)。 -->
      <checksumPolicy>warn</checksumPolicy>
    </releases>
    <!--如何处理远程仓库里快照版本的下载。有了releases和snapshots这两组配置,POM就可以在每个单独的仓库中,为每种类型的构件采取不同的策略。例如,可能有人会决定只为开发目的开启对快照版本下载的支持。参见repositories/repository/releases元素 -->
    <snapshots>
      <enabled />
      <updatePolicy />
      <checksumPolicy />
    </snapshots>
    <!--远程仓库URL,按protocol://hostname/path形式 -->
    <url>http://snapshots.maven.codehaus.org/maven2</url>
    <!--用于定位和排序构件的仓库布局类型-可以是default(默认)或者legacy(遗留)。Maven 2为其仓库提供了一个默认的布局;然而,Maven 1.x有一种不同的布局。我们可以使用该元素指定布局是default(默认)还是legacy(遗留)。 -->
    <layout>default</layout>
  </repository>
</repositories>

2.3Maven工程简介

1.创建Maven工程

我们可以通过在命令行创建Maven工程,也可以通过IDEA创建Maven工程。 打开命令行窗口,跳转到 D:maven 目录,执行以下 mvn 命令。

代码语言:javascript复制
mvn archetype:generate -DgroupId=edu.hncj -DartifactId=helloMaven -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

参数说明:

代码语言:javascript复制
DgroupId: 项目组 ID,通常为组织名或公司网址的反写。
DartifactId: 项目名。
DarchetypeArtifactId: 指定 ArchetypeId,maven-archetype-quickstart 用于快速创建一个简单的 Maven 项目。
DinteractiveMode: 是否使用交互模式。

需要注意的是,每个Maven工程都需要有一个唯一的定位坐标,即上述的GAV(groupId: 项目组 ID,DartifactId: 项目名, Version 唯一发行版本号)

2.Maven工程目录

工程结构:约定优于配置 约定优于配置(Convention Over Configuration)是 Maven 最核心的涉及理念之一 ,Maven对项目的目录结构、测试用例命名方式等内容都做了规定,凡是使用 Maven 管理的项目都必须遵守这些规则。 Maven 项目构建过程中,会自动创建默认项目结构,开发人员仅需要在相应目录结构下放置相应的文件即可。 例如,下表显示了项目源代码文件,资源文件和其他配置在 Maven 项目中的默认位置。

代码语言:javascript复制
  文件      	目录                
  Java 源代码	src/main/java     
  资源文件    	src/main/resources
  测试源代码   	src/test/java     
  测试资源文件  	src/test/resources
  打包输出文件  	target            
  编译输出文件  	target/classes    

2.4Maven常用命令

代码语言:javascript复制
1、mvn compile 编译,将Java 源程序编译成 class 字节码文件。
2、mvn test 测试,并生成测试报告
3、mvn clean 将以前编译得到的旧的 class 字节码文件删除
4、mvn pakage 打包,动态 web工程打 war包,Java工程打 jar 包。
5、mvn install 将项目生成 jar 包放在仓库中,以便别的模块调用

2.5Maven pom.xml介绍

参考资源: https://blog.csdn.net/weixin_38569499/article/details/91456988 https://blog.csdn.net/liuxiao723846/article/details/106578518

常用标签:

modelVersion maven的模型版本,跟随maven定义,一般不能修改。 groupId 项目的组织,一般是顶级域名名称+公司或者组织名称,如果你们公司的域名为www.abc.com,那你们的项目组织最好就以com.abc命名。 artifactId 项目的名称,也是项目之间引进依赖的重要标识。像有个dubbo项目,dubbo项目可能又关联了许多子项目,所以artifactId就会定义有dubbo、dubbo-config这样的工程。 version 项目的版本,项目迭代开发,可能经历许多个版本,靠这个定义,默认是打包的组成部分,如dubbo-2.8.4.jar。另外,版本有两个概念,0.0.1-SNAPSHOT这样的是快照版本,0.0.1-RELEASE或者不带SNAPSHOT的就是RELEASE版本。 packaging 打包类型,有这几种类型:pom, jar, maven-plugin, ejb, war, ear, rar, par,默认不填就是jar包,一般常用的是pom、jar、war。 properties 配置公共属性,如spring-web,spring-aop你要依赖这两个,它们肯定是同一个版本的如4.5.0,可以把版本号放在属性上统一管理,也方便维护。 dependecies 配置工程的依赖信息 builds 用来管理执行maven声明周期的,包括plugins,maven-dependency-plugin,resources

2.6Maven 工程案例-生成二维码

1.基于IDEA或是Eclipse构建Maven工程

设定GAV坐标: edu.hncj VIP01 1.0-SNAPSHOT

添加pom依赖

在工程下的pom.xml中,新增如下标签:

代码语言:javascript复制
<dependencies>
		<!-- 定义二维码生成的库-->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.3.1</version>
        </dependency>
</dependencies>

<build>
<plugins>
			<!-- 定义maven的打包编译插件 -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.6.0</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>

        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.1.1</version>

        <configuration>
<!--          <archive>-->
<!--            <manifest>-->
<!--              <mainClass>org.example.HttpClientTest</mainClass>-->
<!--            </manifest>-->
<!--          </archive>-->

          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <encoding>UTF-8</encoding>

        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
</build>
编写Java代码

edu.hncj.VIP01包下,创建QRCodeGenerator类,内容如下:

代码语言:javascript复制
package edu.hncj.VIP01;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

public class QRCodeGenerator {
     public static byte[] createQRCode(int width, int height, String content) throws WriterException, IOException {
// 二维码基本参数设置
        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");// 设置编码字符集utf-8
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);// 设置纠错等级L/M/Q/H,纠错等级越高越不易识别,当前设置等级为最高等级H
        hints.put(EncodeHintType.MARGIN, 0);// 可设置范围为0-10,但仅四个变化0 1(2) 3(4 5 6) 7(8 9 10)
// 生成图片类型为QRCode
        BarcodeFormat format = BarcodeFormat.QR_CODE;
// 创建位矩阵对象
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, format, width, height, hints);
// 设置位矩阵转图片的参数
//        MatrixToImageConfig config = new MatrixToImageConfig(Color.black.getRGB(), Color.white.getRGB());
// 位矩阵对象转流对象
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        MatrixToImageWriter.writeToStream(bitMatrix, "png", os);
        return os.toByteArray();

    }

    public static void main(String[] args) throws WriterException, IOException {
        byte[] b = createQRCode(100, 100, "遇见最好的自己!");
        OutputStream os = new FileOutputStream("E:\bestme.png");
        os.write(b);
        os.close();
    }
}

右键执行,即可运行成功,同时在E盘根目录下,生成bestme.png文件,用微信扫描二维码后,可看到信息 “遇见最好的自己!”

打包生成jar,并且执行

双击maven下的package,会在target生成jar包 进入到G:ideaprojectVIP01targe目录下,输入CMD,然后再命令行窗口输入

代码语言:javascript复制
G:ideaprojectVIP01target>java -cp VIP01-1.0-SNAPSHOT-jar-with-dependencies.jar edu.hncj.VIP01.QRCodeGenerator

执行代码,会在E盘根目录下生成bestme.png图片

3.Git专题

3.1Git简介

Git是目前世界上最先进的分布式版本控制系统(没有之一)。 Git有什么特点?简单来说就是:高端大气上档次!由linux之父Linus编写。

3.2工作区、暂存区、本地仓库、远程仓库

Git有 workspace: 工作区 index/Stage: 暂存区 Repository: 本地仓库 Remote: 远程仓库 四个区域,具体作业如下图:

平时我们写的代码都是在工作区,执行add命令后就是提交到了暂存区,再执行commit命令后就把代码提交到了版本库了,最后再执行push命令把本地代码提交到远程版本库。下图也基本是这个意思。

3.3Git安装

到Git官网下载,网站地址:https://git-scm.com/downloads

下一步安装即可

安装完成,配置用户名和邮箱

代码语言:javascript复制
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"

查看用户名和邮箱地址

代码语言:javascript复制
$ git config user.name
$ git config user.email

修改局部用户名和邮箱地址:

代码语言:javascript复制
$ cd ~/you project                       
$ git config user.name  "username"      
$ git config user.email "email"   

3.4 Git基本命令

1. 初始化一个版本库repository:

版本库可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。

  • 创建一个空目录:
代码语言:javascript复制
$ mkdir learngit
$ cd learngit
  • 通过git init命令把这个目录变成Git可以管理的仓库:
代码语言:javascript复制
$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/

瞬间Git就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository),细心的读者可以发现当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。 如果你没有看到.git目录,那是因为这个目录默认是隐藏的,用ls -ah命令就可以看见。

2.把文件添加到版本库

在版本库learngit的目录下,编写一个readme.txt文件,内容如下:

代码语言:javascript复制
Git is a version control system.
Git is free software.

一定要放到learngit目录下(子目录也行),因为这是一个Git仓库,放到其他地方Git再厉害也找不到这个文件。

和把大象放到冰箱需要3步相比,把一个文件放到Git仓库只需要两步。

第一步,用命令git add告诉Git,把文件添加到仓库:

代码语言:javascript复制
$ git add readme.txt

执行上面的命令,没有任何显示,这就对了,Unix的哲学是“没有消息就是好消息”,说明添加成功。

第二步,用命令git commit告诉Git,把文件提交到仓库:

代码语言:javascript复制
$ git commit -m "wrote a readme file"
[master (root-commit) eaadf4e] wrote a readme file
 1 file changed, 2 insertions( )
 create mode 100644 readme.txt
3.时光穿梭机

修改readme.txt文件,改成如下内容:

代码语言:javascript复制
Git is a distributed version control system.
Git is free software.

现在,运行git status命令看看结果:

代码语言:javascript复制
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")

git status命令可以让我们时刻掌握仓库当前的状态,上面的命令输出告诉我们,readme.txt被修改过了,但还没有准备提交的修改。 用git diff这个命令查看具体的修改内容:

代码语言:javascript复制
  $ git diff readme.txt 
    diff --git a/readme.txt b/readme.txt
    index 46d49bf..9247db6 100644
    --- a/readme.txt
        b/readme.txt
    @@ -1,2  1,2 @@
    -Git is a version control system.
     Git is a distributed version control system.
     Git is free software.

git diff顾名思义就是查看difference,显示的格式正是Unix通用的diff格式,可以从上面的命令输出看到,我们在第一行添加了一个distributed单词。

知道了对readme.txt作了什么修改后,再把它提交到仓库就放心多了,提交修改和提交新文件是一样的两步,第一步是git add:

代码语言:javascript复制
$ git add readme.txt

同样没有任何输出。在执行第二步git commit之前,我们再运行git status看看当前仓库的状态:

代码语言:javascript复制
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   readme.txt

git status告诉我们,将要被提交的修改包括readme.txt,下一步,就可以放心地提交了:

代码语言:javascript复制
$ git commit -m "add distributed"
[master e475afc] add distributed
 1 file changed, 1 insertion( ), 1 deletion(-)

提交后,我们再用git status命令看看仓库的当前状态:

代码语言:javascript复制
$ git status
On branch master
nothing to commit, working tree clean

Git告诉我们当前没有需要提交的修改,而且,工作目录是干净(working tree clean)的。

小结

  • 要随时掌握工作区的状态,使用git status命令。
  • 如果git status告诉你有文件被修改过,用git diff可以查看修改内容。
4. 版本归退

查看历史提交记录: 版本控制系统肯定有某个命令可以告诉我们历史记录,在Git中,我们用git log命令查看:

代码语言:javascript复制
$ git log
commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master)
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Fri May 18 21:06:15 2018  0800

    append GPL

commit e475afc93c209a690c39c13a46716e8fa000c366
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Fri May 18 21:03:36 2018  0800

    add distributed

commit eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Fri May 18 20:59:18 2018  0800

    wrote a readme file

git log命令显示从最近到最远的提交日志,我们可以看到3次提交,最近的一次是append GPL,上一次是add distributed,最早的一次是wrote a readme file。

如果嫌输出信息太多,看得眼花缭乱的,可以试试加上–pretty=oneline参数:

代码语言:javascript复制
$ git log --pretty=oneline
1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) append GPL
e475afc93c209a690c39c13a46716e8fa000c366 add distributed
eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 wrote a readme file

回归历史版本 首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交1094adb…(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD,上上一个版本就是HEAD,当然往上100个版本写100个比较容易数不过来,所以写成HEAD~100。

现在,我们要把当前版本append GPL回退到上一个版本add distributed,就可以使用git reset命令:

代码语言:javascript复制
$ git reset --hard HEAD^
HEAD is now at e475afc add distributed

–hard参数有啥意义?这个后面再讲,现在你先放心使用。 备注:如果版本回滚后,git log会丢失之后的记录,也就是说无法再查看到当前版本之后的版本了,这时可采用git reflog命令,该命令可以记录每一次操作

Git提供了一个命令git reflog用来记录你的每一次命令:

代码语言:javascript复制
$ git reflog
e475afc HEAD@{1}: reset: moving to HEAD^
1094adb (HEAD -> master) HEAD@{2}: commit: append GPL
e475afc HEAD@{3}: commit: add distributed
eaadf4e HEAD@{4}: commit (initial): wrote a readme file

从命令的历史执行记录可以看到每一次的变化,这样就可以回滚版本到指定的版本了。

总结下:

  • HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id。
  • 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
  • 要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。
5 其它命令

命令git checkout 命令git checkout – readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况: 一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态; 一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。 总之,就是让这个文件回到最近一次git commit或git add时的状态。

命令git rm 从版本库中删除该文件,那就用命令git rm删掉,并且git commit:

代码语言:javascript复制
$ git rm test.txt
rm 'test.txt'

$ git commit -m "remove test.txt"
[master d46f35e] remove test.txt
 1 file changed, 1 deletion(-)
 delete mode 100644 test.txt

现在,文件就从版本库中被删除了。

如果删错了,可以把误删的文件从版本库中恢复到最新版本:

代码语言:javascript复制
$ git checkout -- test.txt

git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

3.5远程仓库

添加远程仓库 假设你已经在本地创建了一个Git仓库后,又想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步,这样,GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作,真是一举多得。

把已有的本地仓库与远程仓库联在本地的learngit仓库下运行命令:

代码语言:javascript复制
$ git remote add origin git@github.com:michaelliao/learngit.git

请千万注意,把上面的michaelliao替换成你自己的GitHub账户名,否则,你在本地关联的就是我的远程库,关联没有问题,但是你以后推送是推不上去的,因为你的SSH Key公钥不在我的账户列表中。

添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。

下一步,就可以把本地库的所有内容推送到远程库上:

代码语言:javascript复制
$ git push -u origin master
Counting objects: 20, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (20/20), 1.64 KiB | 560.00 KiB/s, done.
Total 20 (delta 5), reused 0 (delta 0)
remote: Resolving deltas: 100% (5/5), done.
To github.com:michaelliao/learngit.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。

由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

推送成功后,可以立刻在GitHub页面中看到远程库的内容已经和本地一模一样:

从远程库克隆

上次我们讲了先有本地库,后有远程库的时候,如何关联远程库。 现在,假设我们从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆。 现在,远程库已经准备好了,下一步是用命令git clone克隆一个本地库:

代码语言:javascript复制
$ git clone git@github.com:michaelliao/gitskills.git
Cloning into 'gitskills'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 3
Receiving objects: 100% (3/3), done.

注意把Git库的地址换成你自己的,然后进入gitskills目录看看,已经有README.md文件了:

代码语言:javascript复制
$ cd gitskills
$ ls
README.md

如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了。

你也许还注意到,GitHub给出的地址不止一个,还可以用https://github.com/michaelliao/gitskills.git这样的地址。实际上,Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。

使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。

小结

要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone命令克隆。

Git支持多种协议,包括https,但ssh协议速度最快。

3.6Git的常用命令汇总

简易的命令行入门教程:

Git 全局设置:

代码语言:javascript复制
git config --global user.name "你的用户名"
git config --global user.email "你的邮箱"

创建 git 仓库:

代码语言:javascript复制
mkdir gittest1
cd gittest1
git init
touch README.md
git add README.md
git commit -m "first commit"
git remote add origin2 git@gitee.com:你的用户名/gittest1.git
git push -u origin master

已有仓库?

代码语言:javascript复制
cd existing_git_repo
git remote add origin git@gitee.com:你的用户名/gittest1.git
git push -u origin master

总结

本文主要分享了Java打包,Maven的安装与使用,Git的安装与使用,可能内容不够全面,但尽可能在较段的时间内,给读者提供上诉三种技术的基本面貌。 如果有什么问题,欢迎及时留言,看到会及时回复。

0 人点赞