VIP创新项目1课程总结2021-2022学年第1学期
1. Java基础
1.1 Java代码是如何执行的
参考: https://zhuanlan.zhihu.com/p/92906774 Java执行过程如下图:
- 在指定目录下,编写Java代码,Hello.java源代码如下:
class Hello{
public static void main(String[] agrs){
System.out.println("hello");
}
}
- 编译java源代码 当java源程序编码结束后,就需要编译器编译。 安装好jdk后,我们打开jdk目录,有两个.exe文件,即javac.exe(编译源代码,xxx.java文件) 和 java.exe(执行字节码,xxx.class文件).
用命令行进入到该目录下,编译这个文件javac Hello.java
代码语言:javascript复制F:你的工程所在路径>javac Hello.java
- 将编译后的Hello.class文件打成jar包 jar -cvf hello.jar Hello.class c表示要创建一个新的jar包,v表示创建的过程中在控制台输出创建过程的一些信息,f表示给生成的jar包命名
F:你的工程所在路径> jar -cvf hello.jar Hello.class
已添加清单
正在添加: Hello.class(输入 = 409) (输出 = 280)(压缩了 31%)
- 运行jar包 java -jar hello.jar 这时会报如下错误 hello.jar中没有主清单属性
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
- 最后一样一定要回车,空一行,不然无法识别最后一行的配置。
- Manifest-Version、Main-Class和Class-Path后面跟着一个英文的冒号,冒号后面必须跟着一个空格,然后才是版本号、类和ClassPath。
- Class-Path中的各项应使用空格分隔,不是逗号或分号。
- Class-Path中如果有很多项,写成一行打包的时候会报错line too long,这时需要把Class-Path分多行写。注意:从第二行开始,必须以两个空格开头,三个以上我没试过,不过不用空格开头和一个空格开头都是不行的,我已经试过了。
- Class-Path写完之后最后一定要有一个空行。
- 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都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
- 创建一个空目录:
$ mkdir learngit
$ cd learngit
- 通过git init命令把这个目录变成Git可以管理的仓库:
$ 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的安装与使用,可能内容不够全面,但尽可能在较段的时间内,给读者提供上诉三种技术的基本面貌。 如果有什么问题,欢迎及时留言,看到会及时回复。