Maven-Scope

compile(编译范围)默认就是compile,什么都不配置也就是意味着compile。compile表示被依赖项目需要参与当前项目的编译,当然后续的测试,运行周期也参与其中,是一个比较强的依赖。打包的时候通常需要包含进去。 test(测试范围)表示依赖项目仅仅参与测试相关的工作,包括测试代码的编译,执行。比较典型的如junit。 runntime(运行时范围)表示被依赖项目无需参与项目的编译,不过后期的测试和运行周期需要其参与。与compile相比,跳过编译而已, 说实话在终端的项目(非开源,企业内部系统)中,和compile区别不是很大。比较常见的如JSR×××的实现,对应的API jar是compile的, 具体实现是runtime的,compile只需要知道接口就足够了。Oracle jdbc驱动架包就是一个很好的例子,一般scope为runntime。 另外runntime的依赖通常和optional搭配使用,optional为true。我可以用A实现,也可以用B实现。 provided(已提供范围)表示打包的时候可以不用包进去,别的设施(Web Container)会提供。事实上该依赖理论上可以参与编译,测试,运行等周期。相当于compile,但是在打包阶段做了exclude的动作。 例如一个web 应用,可能在编译 classpath 中需要可用的Servlet API 来编译一个servlet,但是不会在打包好的WAR 中包含这个Servlet API; 这个Servlet API JAR 由应用服务器或者servlet 容器提供。已提供范围的依赖在编译classpath (不是运行时)可用。它们不是传递性的,也不会被打包。 system(系统范围)system范围依赖与provided 类似,但是必须显式的提供一个对于本地系统中JAR 文件的路径。这么做是为了允许基于本地对象编译, 而这些对象是系统类库的一部分。这样的构件应该是一直可用的,Maven 也不会在仓库中去寻找它。如果将一个依赖范围设置成系统范围,必须同时提供一个 systemPath 元素。注意该范围是不推荐使用的(应该一直尽量去从公共或定制的 Maven 仓库中引用依赖)。 依赖传递A–>B–>C 当前项目为A,A依赖于B,B依赖于C,当C的Scope是test或者provided时,C直接被丢弃,A不依赖C; 否则A依赖C,C的Scope继承于B的Scope。

June 26, 2020 · 1 min · jiezi

Maven-DependencyManagerment

在项目顶层的POM文件中,会看到dependencyManagement元素。通过它来管理jar包的版本,让子项目中引用一个依赖而不用显示的列出版本号。Maven会沿着父子层次向上走,直到找到一个拥有dependencyManagement元素的项目,然后它就会使用在这个dependencyManagement元素中指定的版本号。 dependencies即使在子项目中不写该依赖项,那么子项目仍然会从父项目中继承该依赖项(全部继承)dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。<dependencies>中的jar直接加到项目中,管理的是依赖关系(如果有父pom,子pom,则子pom中只能被动接受父类的版本);<dependencyManagement>主要管理版本,对于子类继承同一个父类是很有用的,集中管理依赖版本不添加依赖关系,对于其中定义的版本,子pom不一定要继承父pom所定义的版本。

June 26, 2020 · 1 min · jiezi

Maven多模块报错-If-you-want-an-embedded-database-H2-HSQL-or-Derby

情景一个Maven单模块项目改造为多模块项目后,发现报错: ***************************APPLICATION FAILED TO START *************************** Description: Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine a suitable driver class Action: Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active). Process finished with exit code 1一种可行的解决方案如果是Maven多模块项目,查看IDEA右上角Edit Configurations -> Use classpath of module,此栏应为 包含程序入口的xxxApplication.java和application.yml的module: ...

June 21, 2020 · 1 min · jiezi

2020maven高级

笔记地址:https://img.zhugexuetang.com/...课件地址:https://img.zhugexuetang.com/...课程大纲:https://img.zhugexuetang.com/... maven依赖冲突的解决办法maven构建SSM项目

June 20, 2020 · 1 min · jiezi

maven打包提示Failed-to-execute-goal

这种一般就是测试用例执行出错导致的解决办法:1.使测试用例跑通,不报错2.不执行测试一是命令行 mvn clean package -Dmaven.test.skip=true二是写入pom文件 <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.18.1</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin> PS:欢迎小伙伴加入我的技术交流QQ群 1057838553

June 18, 2020 · 1 min · jiezi

maven项目如何引入第三方JAR包

近期项目开发中使用到了第三方提供的OTP硬件,其官方同时提供了jar包。而我们当前的项目为标准的maven项目。如何在maven项目中引入第三方jar包呢? 带着问题去搜索能够找到一大把答案,stackoverflow的相关问题发表于9年前,最佳答案获取了1100多个赞。但由于时间过于久远,该方法经测试虽然在开发过程中可行,但项目一旦打包便会发生 类无法成功加载 的错误。 经测试以下方案无论是在开发中,还是在项目打包后,都可以成功的在maven项目引用jar包。 复制文件将第三方的jar包复制到项目的资源文件夹中,比如:src/main/resources/lib 添加本地仓库打开项止pom.xml文件,添加以下信息: <project>... <repositories> <repository> <id>local-maven-repository</id> <url>file://${basedir}/src/main/resources/lib/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories>...</project>其中url中的${basedir}代表当前pom.xml文件所在的文件夹。${basedir}/src/main/resources/lib/即为存放第三方jar包的位置。 添加依赖打开pom.xml,添加第三方jar包依赖。比如: <dependency> <groupId>com.mengyunzhi.core</groupId> <artifactId>Share</artifactId> <version>1.0</version> </dependency>groupId填写第三方包的package名称;artifactId可以填写要引用的类名;version可以任意填写,但必须有。 至此便可以在项目中正常的使用该jar包提供的功能了。 作者信息:河北工业大学梦云智开发团队 潘杰

June 18, 2020 · 1 min · jiezi

这篇文章教会你把个人开发的jar包发布到maven中央仓库

作者:小傅哥博客:https://bugstack.cn - 原创系列专题案例 沉淀、分享、成长,让自己和他人都能有所收获!????前言介绍(19年12月)最近想基于Spring Boot做个开源共享项目,开发一个分布式任务DcsSchedule中间件可以把Schedule增强。那么遇到一个问题希望把Jar包发包到Maven中央仓库,这样需要使用的用户就可以直接引入。 发布准备 内容备注1申请Github帐号: https://github.com用于上传开源代码:https://github.com/fuzhengwei...2GPG生成密钥工具: https://gpg4win.org/download....在后续流程中下载安装生成密钥并上传置服务器,本文使用的服务器是:hkp://keyserver.ubuntu.com:803工单系统: https://issues.sonatype.org负责申请上传资格及完成第一次上传,后续更新不需要使用,相当于一个启动装置4构件仓库: https://oss.sonatype.org上传的jar包会先存放到这里,在这里进行 Release 后即可发布到maven中央仓库,也可以本地设置自动发布5镜像仓库: http://search.maven.org最终成功发布的jar可以在这里搜到6Maven仓库:https://mvnrepository.com经过几个小时耐心的等待会在Maven仓库中搜到7阿里云仓库:https://maven.aliyun.com阿里云的仓库会同步的快一些8个人域名:https://bugstack.cn这里主要用于工单资格验证(Add a TXT record to your DNS referencing this JIRA ticket: OSSRH-53637 (Fastest))跟着节奏1. 下载安装Gpg生成密钥我们需要一个GPG环境,用来对上传的文件进行加密和签名,保证你的jar包不被篡改 1991年,程序员Phil Zimmermann为了避开政府监视,开发了加密软件PGP。这个软件非常好用,迅速流传开来,成了许多程序员的必备工具。但是,它是商业软件,不能自由使用。所以,自由软件基金会决定,开发一个PGP的替代品,取名为GnuPG。这就是GPG的由来。下载地址:https://gpg4win.org/download.html下载完成后直接安装即可,比较傻瓜式安装很简单,记得选中文(如果你英文硬也可以不选)生成密钥(可以使用命令行生成,也可以直接在操作界面生成) 文件>新建密钥对(Ctrl+N) -- 创建个人 OpenPGP 密钥对 填写个人信息姓名和邮箱 并点击到 新建 填写密钥密码 将公钥上传到目录服务{如果上传失败,则通过:设置(S)->配置Kleopatra(C),修改 OpenPGP密钥服务器为:hkp://keyserver.ubuntu.com:80} 2. 工单系统帐号注册issues.sonatype1. 注册地址:https://issues.sonatype.org/s... 2. 创建工单 项目:Community Support - Open Source Project Repository Hosting概要:发布Jar的名称描述:非必填,最好描述清晰Group Id:org.itatack.middleware & 和你的域名有关系,因为后续需要使用域名验证Project URL:Github项目站点(https://github.com/fuzhengwei...SCM url:源码仓库(https://github.com/fuzhengwei...3. 配合人工审核当创建完工单后,会收到信息反馈(国外与我们有时间差,半夜的时候他们审核的更快); ```javaDo you own the domain itstack.org? If so, please verify ownership via one of the following methods:Add a TXT record to your DNS referencing this JIRA ticket: OSSRH-53637 (Fastest)Setup a redirect to your Github page (if it does not already exist)If you do not own this domain, please read:http://central.sonatype.org/pages/choosing-your-coordinates.htmlYou may also choose a groupId that reflects your project hosting, in this case, something like io.github.fuzhengwei or com.github.fuzhengweiWould you like to use a free managed security reporting service (recommended)?Put https://hackerone.com/central-security-project/reports/new as your project's security issue reporting URL. We'll take care of the rest.For more details on the Central Security Project, visit https://www.sonatype.com/central-security-project```![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91c2VyLWdvbGQtY2RuLnhpdHUuaW8vMjAxOS8xMi83LzE2ZWRmMGI3ZmZjYTAzZWM?x-oss-process=image/format,png)配置域名验证签名;TXT 指向问题域:https://issues.sonatype.org/b... ...

June 18, 2020 · 3 min · jiezi

Maven

Maven一.Maven简介1.1 何为mavenMaven可翻译为"知识的积累" or"专家",是一款成功的开源跨平台的项目管理工具,无论小型的开源类库项目,还是大型的企业级应用;无论传统的瀑布式开发,还是流行的敏捷模式,Maven都能大显身手.1.1.1 构建工具 我们一直在不停的寻找避免重复的方法,设计的重复,编码的重复,文档的重复,当然还有构建的重复.Maven最大化的消除了构建的重复,抽象了构建生命周期,并且为绝大部分的构建任务提供了已实现的插件,我们不需要再定义过程,甚至不需要去实现这些过程中的一些任务,只需要遵循Maven中的约定. 同时Maven帮助我们标准化构建过程,以前十个项目可能有十种构建方式,有了Maven后,所有项目的构建命令都是一直且简单的.因此Maven作为一个构建工具: 可以帮我们自动化构建,可以帮我们抽象构建过程提供构建任务是实现跨平台对外提供一直的操作接口1.1.2 不仅仅是构建工具 Maven不仅是构建工具,还是一个依赖管理工具和项目信息管理工具,提供中央仓库来帮忙我们自动下载构建,通过引入一套经纬机制来系统准确的定位每一个构建(artifact). 1.1.3 Maven 在Maven之前,有过程式的Make和Ant,开发者需要显示的指定每一个目标,以及完成该目标所需要执行的任务.针对每一个项目,开发者都需要重新编写这一过程,而其中就隐含着大量重复. 而Maven是声明式的,项目构建过程和过程各个阶段所需的工作都由插件实现,并且大部分插件都是现成的,开发者只需要声明项目的基本元素,Maven就执行内置的,完整的构建过程. 二.Maven的使用2.1 pom文件 Maven项目的核心是pom.xml,POM(Project Object Model,项目对象模型)定义了项目的基本信息,用于描述项目如何构建,声明项目依赖等. <modelVersion>4.0.0</modelVersion>:modelVersion指定了当前Pom模型的版本,固定为4.0.0<groupId>com.lsy</groupId>:groupId定义了项目属于哪个组,这个组往往和项目所在的组织和公司相关 <artifactId>hello-world</artifactId>:artifactId定义了当前Maven项目在组中唯一的ID <version>1.0-SNAPSHOT</version>:version指定了Hello World项目当前的版本,其中SNAPSHOT意为快照,说明该项目还处于开发中 <name>Maven Hello World Project</name>:name元素声明了一个对于用户更为友好的项目名称.非必须 当运行mvn clean compile命令:clean告诉Maven清理输出目录target/,compile告诉Maven编译项目主代码,从输出中看到Maven首先执行clean:clean任务,删除target/目录(默认情况下,Maven构建的所有输出都在target目录中,接着执行resources:resources任务(未定义项目资源),最后执行compiler:compile任务,将项目主代码编译至target/classes目录 其中clean:clean,resources:resources和compiler:compile对应了Maven插件及插件目标,比如clean:clean是clean插件的clean目标,compiler:compile是compiler插件的compile目标 2.2 测试 首先添加Junit依赖 <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>test</scope> </dependency> <dependencies> 其中scope元素为依赖范围,若依赖范围为test则表示该依赖只对测试有效,如果不声明依赖范围,则默认是compile,表示该依赖对主代码和测试代码均有效 当运行mvn clean test命令,Maven实际执行的不止test任务,而是clean:clean,resources:resources,compiler:compile,resources:testResources以及compiler:testCompile,即在执行测试之前,会先自动执行项目资源处理,主代码编译,测试资源处理,测试代码编译等工作,这是Maven生命周期的一个特性. 由于Maven核心插件之一compiler插件默认支持Java1.3,因此需要配置插件支持Java1.8 <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> ...

May 31, 2020 · 11 min · jiezi

修改maven包本地默认位置

前言这段时间上岸了,就有时间整理电脑的资料(强迫症重度患者),就向maven以及gradle的仓库位置动手了。 目的改变maven的默认位置 步骤修改maven的配置文件setting.xml(maven安装位置:conf) 将localRepository的标签值修改成想要设置的目录。 复制修改后的setting.xml到仓库所在位置并重启(非必须)修改idea中maven设置Setting->Build->Build Tools->Maven 修改圈起来的三个配置项就可以了 本文首发于cartoon的博客转载请注明出处:https://cartoonyu.github.io/cartoon-blog/post/pm/修改maven包本地默认位置/

October 17, 2019 · 1 min · jiezi

Maven项目分析剔除无用jar引用

一、为什么要做这件事?项目持续研发,不停地在上面新增功能,新增特性,引入新的框架和组件,jar包依赖多并且复杂,再加上需求各种变更,有不少已经存在的功能下线,但jar包依赖没人管,还是放在项目的pom.xml文件里。项目持续的时间一长,经常会出现项目打包要求内存多,时间慢的问题,如何分析项目中哪些依赖是有用的,哪些可以剔除的,一方面减轻打包内存占用多,时间慢的问题,另一方面照顾研发童鞋的强迫症问题(容不得半点无用jar包在我的项目里),这事就可以提上日程了。 二、怎么做?如果是Maven项目,执行起来还是比较简单,Maven自己提供了一个检测工具,输入命令即可。在IDEA中,切换到Terminal窗口,或者用命令行打开相应工程目录,直接输入 mvn dependency:analyze查看控制台输出的日志,重点关注这两部分: [WARNING] Used undeclared dependencies found:[WARNING] com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile[WARNING] com.fasterxml.jackson.core:jackson-databind:jar:2.9.9:compile[WARNING] io.jsonwebtoken:jjwt:jar:0.9.0:compile[WARNING] org.apache.rocketmq:rocketmq-common:jar:4.5.2:compile[WARNING] org.springframework:spring-beans:jar:5.1.8.RELEASE:compile[WARNING] com.google.code.gson:gson:jar:2.8.0:compile[WARNING] org.springframework.boot:spring-boot:jar:2.1.6.RELEASE:compile[WARNING] com.fasterxml.jackson.core:jackson-core:jar:2.9.9:compile[WARNING] org.springframework:spring-core:jar:5.1.8.RELEASE:compile[WARNING] org.apache.rocketmq:rocketmq-remoting:jar:4.5.2:compile[WARNING] Unused declared dependencies found:[WARNING] org.projectlombok:lombok:jar:1.16.20:provided[WARNING] org.springframework.boot:spring-boot-starter-test:jar:2.1.6.RELEASE:testUsed undeclared dependencies found间接依赖,就是说你在当前项目工程的pom.xml里没有直接声明,这个依赖是由你声明过的dependency里的pom.xml依赖传递得来的。例如org.apache.rocketmq:rocketmq-common:jar:4.5.2:compile是你引用了这个: <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client</artifactId> <version>4.5.2</version></dependency>Maven本来就是这样用的,也不建议说你把这部分引用拷贝到你的pom.xml里,一般来说这部分的WARNING可以忽略。 Unused declared dependencies found无用依赖,这个指我们在pom.xml声明了这个jar包的依赖,但在项目工程里没有使用到,这个不是我们此次关注的重点,确定不需要,就可以剔除掉这个依赖,Reimport后这个jar包就从我们项目中剔掉了。 三、什么时候做?1)新项目建立时,引用jar包时要慎重,不要一股脑儿直接拷贝老项目的依赖,避免后期又花时间来剔除。2)功能代码重构时,可以适当做一次剔除,因为后面还有自测,提交测试环节,如果有误删,测试的时候能发现。 四、有什么风险要注意的?1)这个检测的结果仅供参考,有时也不准确,如上文提及的org.projectlombok:lombok:jar:1.16.20:provided,实际上在项目中有使用到它的注解@Data,这个属于误判。要注意剔除依赖后多测试,工具毕竟有毕竟的缺陷性。2)如果童鞋们接手遗留的老项目时,这种问题肯定很多,但刚接手时不建议做这个操作,因为本身对项目不熟悉,上来就删东西导致问题会浪费很多时间和精力搞定依赖的问题,这块东西建议暂时先不要动。 五、补充一个小插件查看pom.xml的依赖关系时,可以在IDEA上安装maven help插件,可以直观地看到各jar依赖关系 专注Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号

October 15, 2019 · 1 min · jiezi

Eclipse创建Maven管理的Web项目

动态的web项目 部署映射项目名 右键 ,properties的Deployment Assembly,这是部署的映射,jar包在lib目录里、src映射到 WEB-INF/classes中、/WebContent映射到 / 根目录中。 --------------------------------------------------------------------------------------------普通 web项目 直接创建一个新的 Dynamic Web ProjectTarget runtime:服务器的运行环境Dynamic Web module version :动态web模块的版本,即JavaEE里的servlet版本下一步 src 编写完后默认的输出到的文件中(即buildclasses)下一步 根目录、web资源目录、及可选项是否创建.xml文件,也可以创建项目后,项目右键 在JavaEE Tools 中也可以生成.xml文件完成在Eclipse的Window的Show View中的Navigator可以显示隐藏文件,如.classpath和.projet文件,build下的classes文件夹等(其中MFTA-INF是自动生成的东西,可以删除) --------------------------------------------------------------------------------------------maven web项目(注意网络) 注意每一步更新项目,项目右键Maven,Update Project,快捷键Alt+F5① 创建一个简单的Maven项目,再配置成web项目创建一个新的Maven Project,选择Create a simple project,创建一个简单的项目next Group Id:一般公司域名的反写,Artifact:项目名finnish后续步骤: 步骤1:这时候创建的项目,其JDK的1.5,可以在 pom.xml 文件中进行配置在properties标签内配置在maven官网的Maven Plugins中的compiler(插件)里,Example中 有个-source -target里有样例 步骤2:修改打包方式 pom.xml文件中 步骤3:在自动生成的src/main/webapp下手动创建WEB-INF文件夹WEB-INF下新建web.xml文件注意:maven的web项目的WEB-INF下不用新建classes和lib目录 步骤4:添加服务器运行环境(主要是servlet-api.jar)第一种,项目名右键的构建路径里的Add Library 中的server runtime直接引入本地的服务器第二种,在pom文件中使用依赖引入servlet相关jar包dependencies标签来管理依赖(provided是指这个jar包由本地服务器提供,打包时不会打包,默认是compile) 步骤5:注意映射properties的Deployment Assembly,这里不用修改了 ② 使用Eclipse中自带的Maven的web骨架,来创建项目,再进行配置修改 创建maven项目,不选择创建简单项目,进入选择骨架的页面,选择maven-archetype-webapp,下一步,填写组ID和项目名,完成。默认jdk是1.5,默认版本是2.3 后续步骤: 步骤1:pom中修改jdk版本,与上同理,在自动src/main/webapp/WEB-INF下生成的index.jsp删掉 步骤2:发现src目录显示不全,在构建路径里的Configure Build Path里的Order and Export下,选中缺失的,Down下移就会显示出来 步骤3:修改WEB-INF下的web.xml文件中的容器版本,可以直接复制之前普通web项目的该文件 步骤4:properties中的Project Facets的动态页面模型的版本是2.3,这里不能改,因为这个配置是骨架写在配置文件中的,所以在Navigator的视图下,查看隐藏的.settings文件夹下的project.facet.core.xml中facet="jst..web" 对应行的version改为3.1 ...

October 9, 2019 · 1 min · jiezi

Maven基础教程之插件

这又是一个系列,一个要把Maven讲透的系列,希望能够对大家有帮助!前言上一篇《Maven基础教程之生命周期》中也讲到了,Maven中通过模板方法这样的设计模式,生命周期只“立牌坊”,而实际上是插件在背后默默的奉献着。也就是说,在Maven中,真正的完成生命周期中那些阶段该干的活,都是由插件来做的。所以,从上面的描述,大家也能感受到Maven中插件的重要性了;插件非常重要,所以它的知识点肯定也少不了,对吧;然而,我的这篇关于插件的文章,我并不打算长篇大论的铺开来将Maven中的插件,因为我觉的有些东西,并不是那样的重要,所以,这篇关于插件的文章,点到为止,意会即可! 插件目标?在继续下面的总结之前,我们需要先来理解“插件目标”这个概念。根据我们的开发经验,在开发一个软件时,这个软件肯定会包含很多的功能,并不会一个功能搞一个软件;同理,Maven中的插件也是这样的,比如下图所示: 而这里的每一个功能就对应一个插件目标。比如maven-dependency-plugin插件有十多个目标,每个目标对应一个功能。在《Maven基础教程之依赖》中讲到的dependency:list、dependency:tree和dependency:analyze这些都是插件目标,这是一种通用的写法,冒号前面是插件前缀,冒号后面是该插件的目标。 插件绑定说完了插件目标,那这个插件目标到底如何使用呢?上一篇说了生命周期,这个生命周期和插件是相互独立存在的,如果需要插件完成生命周期对应阶段的任何,那就需要将生命周期与插件相互绑定,也就是说需要将生命周期的阶段与插件的目标相互绑定,这样才能完成某个具体的构建任务。 就如上图所示,default生命周期的compile阶段与maven-compiler-plugin插件的compile插件目标,到时候,就由compile插件目标完成default生命周期的compile阶段对应的实际操作。 关于插件绑定,主要分为内置绑定和自定义绑定两大类。 内置绑定我们都知道,为了让Maven开箱即用,Maven开发了很多默认的插件来完成每个生命周期对于阶段的一些工作,同时,也将这些生命周期的一些主要的阶段和这些默认插件的插件目标进行了绑定,这就是内置绑定。对于内置绑定,我们知道有这么一回事,知道Maven的实现原理即可,至于哪个插件的插件目标和那个生命周期的阶段进行内置绑定,有了问题再查也OK的。自定义绑定为了能补充内置绑定的不足,完成更多个性化的任务,Maven社区的大牛开发了很多的插件,当然了,我们自己也可以开发,后面会讲到的。那这些插件如何和Maven的生命周期的阶段进行绑定呢,这就是我们要说的自定义绑定。下面我们通过一个例子来说明自定义绑定: <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.jellythink.HelloWorld.App</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins></build>在POM的build元素下的plugins子元素中声明插件的使用,插件在Maven中同其它包一样,也是作为独立的构建存在,所以也需要通过指定groupId、artifactId和version这三个坐标元素去仓库中定位插件。除了基本的插件坐标声明外,还有插件执行配置,executions下每个execution子元素可以用来配置执行一个任务。上述例子中通过phase配置,将其绑定到package生命周期阶段上,再通过goals配置指定要执行的插件目标,这样自定义插件绑定就完成了。 执行mvn clean install命令,我们就可以看到这样的输出: [INFO] --- maven-shade-plugin:3.2.1:shade (default) @ hello-world ---[INFO] Replacing original artifact with shaded artifact.[INFO] Replacing E:\Code\Spring\helloworld\target\hello-world-1.0-SNAPSHOT.jar with E:\Code\Spring\helloworld\target\hello-world-1.0-SNAPSHOT-shaded.jar可以看到执行了maven-shade-plugin插件的shade插件目标。 有的时候,你会看到有的插件不通过phase元素配置生命周期阶段,插件目标也能够绑定到生命周期中去。这个时候也不要惊讶,这主要是很多插件的目标在编写时已经定义了默认绑定阶段,我们可以通过maven-help-plugin查看插件的详细信息,了解插件目标的默认绑定阶段。执行mvn help:describe -Dplugin=org.apache.maven.plugins:maven-shade-plugin:3.2.1 -Ddetail就可以看到插件的完整信息,比如这个插件有几个插件目标,有哪些参数,默认绑定阶段等,通过查找Bound to phase: package,我们就可以看到默认绑定到哪个阶段。 插件配置我们在实现一个功能时,也会想着通过传递参数来实现更强大的功能。Maven插件也是这样的,我们可以配置插件目标的参数,满足我们对插件更加个性化的要求。对于插件的参数配置,有以下两种常用方式: 通过命令行进行插件配置我们经常看到以下这个命令: mvn clean install -Dmaven.test.skip=true这个就是典型的通过命令行进行插件配置,maven.test.skip是maven-surefire-plugin提供的一个参数,我们通过命令行传入一个true参数,表示跳过执行测试。 参数-D是Java自带的,其功能是通过命令行设置一个Java系统属性。Maven简单的重用了该参数。 ...

October 6, 2019 · 1 min · jiezi

Maven基础教程之仓库

这又是一个系列,一个要把Maven讲透的系列,希望能够对大家有帮助!前言在前面的几篇关于Maven的总结中,都说到只要指定了groupId、artifactId和version坐标信息,就可以从中央仓库中找到对应的jar包。等一下,仓库?大家肯定会问,仓库是什么?这个仓库在哪里?为什么Maven会自动去那个仓库找我要的jar包呢?好的,我知道大家肯定有一堆的疑问,一头雾水,这篇文章就来解决大家的这些疑问,拨开疑雾,对这个“仓库”一探究竟。跟着我的步伐,Let's go! Maven仓库是什么?现在大家想一下之间开发的非Maven项目,是不是在每个项目下面都有一个lib目录。是的,你不用去翻看你以前做的项目了,没有错,没有Maven之前,我们项目依赖的包,我们都会下载下来,统一放到对应项目的lib目录下去。同一个包,比如Spring框架的包,项目A要使用,就拷贝一份到项目A的lib目录下去;项目B也要使用,那就再拷贝一份到项目B的目录下去。这样下去,你会发现同样的依赖包,需要拷贝N份,这样不仅造成了磁盘空间的浪费,而且也难于统一管理。 现在好了,有了Maven,基于Maven的坐标机制,任何Maven项目使用任何一个构件的方式都是完全相同的。在此基础上,Maven可以在某个位置统一存储所有Maven项目共享的包,而这个统一存放依赖包的位置就是仓库。说白了,Maven仓库就是存放依赖包的地方。 有了这个Maven仓库后,上面的问题就有了一个完美的解决方案。基于Maven开发的项目不再各自存储其依赖文件,它们只需要声明这些依赖的坐标,在需要的时候,Maven会自动根据坐标找到仓库中的包,并正确使用它们。 仓库的分类在使用Maven的过程中,我们需要知道Maven去哪里找那个所谓的“仓库”,从而加载依赖。所以,我们就需要知道Maven仓库的分类。 在Maven中,仓库分为以下两类: 本地仓库远程仓库Maven根据依赖坐标去仓库中找对应的包,是遵循这样的一个轨迹: 首先去本地仓库查找,如果本地仓库有对应的依赖包,则直接就使用;如果本地仓库不存在对应包时,或者需要查看是否有更新的包版本时,Maven就会去远程仓库查找,发现需要的构件之后,下载到本地仓库在使用;如果本地仓库和远程仓库都没有需要的包,Maven就会报错。上面简单将Maven仓库进行的分类,但是对于远程仓库,它又分为好几种: 本地仓库上面也说到了Maven根据依赖坐标去仓库中找对应的包是有遵循的轨迹的。Maven最开始都是从本地仓库寻找依赖的包。默认情况下,不管是在Windows还是在Linux上,每个用户在自己的用户目录下都有一个路径名为.m2/repository的仓库目录。这个就是默认的本地仓库地址。 有的时候,用户可能会自定义本地仓库的目录地址(我一般都会这么干)。此时,可以通过编辑~/.m2/settings.xml,设置localRepository元素的值就OK了,比如我的是这样子的: <localRepository>E:/repository</localRepository>这样,该用户的本地仓库地址就被设置成了E:/repository。 中央仓库由于最开始的本地仓库是空的,Maven必须知道至少一个可用的远程仓库,这样才能在执行Maven命令的时候下载到需要的构件。中央仓库就是这样一个默认的远程仓库,Maven的安装文件中自带了中央仓库的配置。使用解压缩工具打开$M2_HOME/lib/maven-model-builder-3.5.0.jar文件,在org\apache\maven\model目录下有一个pom-4.0.0.xml文件,该文件里面有这么一段代码,它配置了默认的中央仓库: <repositories> <repository> <id>central</id> <name>Central Repository</name> <url>https://repo.maven.apache.org/maven2</url> <layout>default</layout> <snapshots> <enabled>false</enabled> </snapshots> </repository></repositories>pom-4.0.0.xml文件是所有Maven项目都会继承的超级POM,这段配置使用id central对中央仓库进行唯一标识,同时设置snapshots元素,其子元素enabled的值为false,表示不从该中央仓库下载快照版本的包。 中央仓库是一个大而全的包仓库,它包含了这个世界上绝大多数流行的开源Java包,以及源码等信息。一般来说,一个简单Maven项目所需要的依赖包都能从中央仓库下载到,这也就解释了为什么Maven能做到“开箱即用”。 私服玩游戏的时候,经常会听到私服。但是在学习Maven的时候,也听到私服,这个就比较特殊了。在Maven中,私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用。整体架构如下图所示: 当Maven需要下载依赖包的时候,它从私服请求,如果私服上不存在该依赖包,则从外部的远程仓库下载,缓存到私服上之后,再为Maven的下载请求提供服务。另外,一些无法从外部仓库下载到的依赖包也能从本地上传到私服上供大家使用。 为啥要用私服呢?肯定是有少好处的。像在我们公司,在全国31个省都有分公司,同时总部研发中心还会开发一堆的公共JAR包,给31个分公司使用,这样通过私服就可以很好的解决研发中心和分公司之间的公共包分发等问题。对于使用私服,它有以下这些优点: 加快Maven构建;我们知道,不停的连接外部仓库下载依赖包是一件非常耗费时间的事情,而私服部署在局域网,则可以大大的降低依赖包的下载时间,提高Maven构建效率;部署第三方包;比如我们公司的研发中心,会开发很多公共的包,而这些包又无法上传至中央仓库,所以这些包部署在私服就再适合不过了。远程仓库配置没有一个平台能够大而全到包含所有的东西,同理,中央仓库也是这样的,虽然它包含了我们需要的大部分的依赖包,但是还是有一些包在中央仓库中是找不到的。这个时候,我们就需要配置一些其它远程仓库来补充中央仓库中没有的依赖包,与中央仓库配合完成工作,当中央仓库也没有对应的依赖包时,Maven则遍历所有的远程仓库。 我们需要在pom.xml中配置即可,比如这样: <project> ...... <!-- 配置远程仓库 --> <repositories> <repository> <id>jboss</id> <name>JBoss Repository</name> <url>http://repository.jboss.com/maven2/</url> <releases> <enabled>true</enabled> <updatePolicy>daily</updatePolicy> </releases> <snapshots> <enabled>false</enabled> <checksumPolicy>warn</checksumPolicy> </snapshots> <layout>default</layout> </repository> </repositories> ......</project>repository:在repositories元素下,可以使用repository子元素声明一个或者多个远程仓库。id:仓库声明的唯一id,尤其需要注意的是,Maven自带的中央仓库使用的id为central,如果其他仓库声明也使用该id,就会覆盖中央仓库的配置。name:仓库的名称,让我们直观方便的知道仓库是哪个,暂时没发现其他太大的含义。url:指向了仓库的地址,一般来说,该地址都基于http协议,Maven用户都可以在浏览器中打开仓库地址浏览构件。releases和snapshots:用来控制Maven对于发布版构件和快照版构件的下载权限。需要注意的是enabled子元素,该例中releases的enabled值为true,表示开启JBoss仓库的发布版本下载支持,而snapshots的enabled值为false,表示关闭JBoss仓库的快照版本的下载支持。根据该配置,Maven只会从JBoss仓库下载发布版的构件,而不会下载快照版的构件。layout:元素值default表示仓库的布局是Maven2及Maven3的默认布局,而不是Maven1的布局。基本不会用到Maven1的布局。其他:对于releases和snapshots来说,除了enabled,它们还包含另外两个子元素updatePolicy和checksumPolicy。元素updatePolicy用来配置Maven从远处仓库检查更新的频率,默认值是daily,表示Maven每天检查一次。其他可用的值包括:never-从不检查更新;always-每次构建都检查更新;interval:X-每隔X分钟检查一次更新(X为任意整数)。 元素checksumPolicy用来配置Maven检查校验和文件的策略。当构建被部署到Maven仓库中时,会同时部署对应的检验和文件。在下载构件的时候,Maven会验证校验和文件,如果校验和验证失败,当checksumPolicy的值为默认的warn时,Maven会在执行构建时输出警告信息,其他可用的值包括:fail-Maven遇到校验和错误就让构建失败;ignore-使Maven完全忽略校验和错误。 大部分公共的远程仓库无须认证就可以直接访问,但我们在平时的开发中往往会架设自己的Maven远程仓库,出于安全方面的考虑,我们需要提供认证信息才能访问这样的远程仓库。配置认证信息和配置远程仓库不同,远程仓库可以直接在pom.xml中配置,但是认证信息必须配置在settings.xml文件中。这是因为pom往往是被提交到代码仓库中供所有成员访问的,而settings.xml一般只存在于本机。因此,在settings.xml中配置认证信息更为安全。比如这样配置: <servers> <server> <id>deploymentRepo</id> <username>repouser</username> <password>repopwd</password> </server></servers>这里的关键是id元素,settings.xml中server元素的id必须与pom.xml中需要认证的repository元素的id完全一致。正是这个id将认证信息与仓库配置联系在了一起。 部署至远程仓库很多时候,我们编译完成后,会将我们的负责的模块包部署至私服,以供其它团队成员使用。那如何将我们的包部署到远程仓库呢? 我们配置项目的pom.xml文件即可,配置如下所示: ...

October 6, 2019 · 1 min · jiezi

Maven基础教程之依赖

这又是一个系列,一个要把Maven讲透的系列,希望能够对大家有帮助!前言在前面的总结中,总是说到依赖这个东西,而且还有看到dependencies这个词在pom.xml文件中的使用,所以很多读者就很迫不及待的想知道这个依赖到底是什么东西?作为Maven中一个非常重要的概念,那到底该如何使用和配置,以及使用过程中有哪些注意事项,而这篇文章就是对Maven中的依赖进行详细的总结,一扫对依赖概念的不解。 依赖的配置在Maven中,是在pom.xml文件中完成依赖的配置,我们先来看看依赖配置的语法。 <project> ... <dependencies> <dependency> <groupId>...</groupId> <artifactId>...</artifactId> <version>...</version> <type>...</type> <scope>...</scope> <optional>...</optional> <exclusions> <exclusion> ... </exclusion> </exclusions> </dependency> ... </dependencies> ...</project>乍一看,这个配置还是蛮复杂的,其实我们常用的没有这么多,而且这些用起来也是非常简单的。根元素project下的dependencies可以包含一个或者多个dependency元素,以声明一个或者多个项目依赖。下面就详细说一下这些配置的含义。 groupId、artifactId和version:依赖的基本坐标,对于任何一个依赖来说,基本坐标是最重要的,Maven根据坐标才能找到需要的依赖;type:依赖的类型,对应于项目坐标定义的packaging,大部分情况下,该元素不必声明,其默认值为jar;scope:依赖的范围,这个内容就比较多一点,下面会专门进行总结;optional:标记依赖是否可选,下面会专门进行总结;exclusions:用来排除传递性依赖,下面会专门进行总结。很多时候,大部分依赖声明只包含groupId、artifactId和version这三个指定基本坐标的元素;而在一些特殊情况下,其它元素至关重要,也就是上面提到的scope、optional和exclusions。下面就对这三个要素进行详细的总结。 依赖范围不知道大家还记不记得在《Maven基础教程之使用入门》中的这段junit依赖代码: <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency></dependencies>这里就指定了scope这个要素的值,那这里指定这个要素有什么含义呢? 我们需要知道,Maven在编译项目主代码的时候需要使用一套classpath。举例来说: 当Maven编译项目主代码的时候如果需要用到spring-core,该文件以依赖的方式被引入到classpath中;当Maven编译和执行测试的时候会使用另外一套classpath,则junit文件也会以依赖的方式引入到测试使用的classpath中;当Maven项目运行时,又会使用一套classpath。所以依赖范围就是用来控制依赖与这三种classpath(编译classpath、测试classpath、运行classpath)的关系。在Maven中,我们可以针对scope要素设置以下依赖范围: compile:编译依赖范围。如果没有指定scope值,就会默认使用该依赖。使用该依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效;test:测试依赖范围。使用此依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目时都无法使用此依赖。对于上面的junit例子,它只有在编译测试代码及运行测试的用例的时候才需要;provided:已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效。最典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经提供,就不需要Maven重复地引入一遍;runtime:运行时依赖范围。使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。最典型的例子就是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。system:系统依赖范围。该依赖与三种classpath的关系和provided依赖范围完全一致。但是,使用system范围的依赖时必须通过systemPath元素显式地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此谨慎使用。system的使用举例: <dependency> <groupId>com.jellythink.BookStore</groupId> <artifactId>BookStore-SSO</artifactId> <version>1.0</version> <scope>system</scope> <systemPath>${basedir}/lib/BookStore-SSO-1.0.jar</systemPath></dependency>对于system系统依赖范围,在进行以上配置以后,编写代码时已经可以引入Jar包中的class了,但是在打包时,由于scope=system,默认并不会将依赖包打进WAR包中,所有需要通过插件进行打包。例如: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.10</version> <executions> <execution> <id>copy-dependencies</id> <phase>compile</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/lib</outputDirectory> <includeScope>system</includeScope> </configuration> </execution> </executions></plugin>会了更好的理解和记忆依赖范围与classpath的关系,将上述内容总结成一张表格。 依赖范围(scope)对于编译classpath有效对于测试classpath有效对于运行时classpath有效例子compileYYYspring-coretest-Y-junitprovidedYY-servlet-apiruntime-YYJDBC驱动实现systemYY-本地的,Maven仓库之外的类库文件依赖传递的几个注意事项说到依赖传递,这里的关系就比较复杂,在没有使用Maven之前,大家是否有这样的开发体验;比如引入了包A,由于我们不知道包A的依赖,只能在编译的时候,根据出错信息,再加入需要的其它依赖,很显然,这样的开发体验是及其糟糕的。而现在有了Maven,Maven中的传递性依赖机制可以很好的解决这一问题。这里就来详细的总结Maven中的依赖传递。 啥是依赖传递在实际项目中,我们肯定会遇到如下图所示的这种依赖情况: A依赖B,B又依赖C。由于基于Maven创建的项目,有了传递性依赖机制,在使用A的时候就不用去考虑A依赖了什么,也不用担心引入多余的依赖。Maven会解析各个直接依赖的POM,将那些必要的间接依赖,以传递性依赖的形式引入到当前的项目中。 依赖传递的范围在传递性依赖中,如上图所示的A依赖B,B依赖C,我们就说A与B是第一直接依赖,B与C是第二直接依赖,C对于A是传递性依赖。第一直接依赖的范围和第二直接依赖的范围决定了传递性依赖的范围,下面通过一张表格来说明这种传递性依赖范围: 对于上面的图,最左面的一列表示第一直接依赖范围,最上面一行表示第二直接依赖范围。比如A对B的依赖scope是compile,B对C的依赖scope是runtime,那么A对C的依赖scope就是runtime。如下图标注所示: 在实际使用过程中,对于这个依赖传递范围的关注还是比较少的,在以后的使用过程中,如果遇到问题,我们应该能想到这里总结的依赖传递范围相关的知识点。 依赖调解先来说一个实际开发过程中经常会遇到的两个问题。 问题一:比如项目A有这样的两个依赖关系: ...

October 6, 2019 · 1 min · jiezi

Maven基础教程之使用入门

这又是一个系列,一个要把Maven讲透的系列,希望能够对大家有帮助!前言说到Maven的入门使用,其实是特别简单的,如果只是说就是能使用,会使用Maven,也许只要短短的一两个小时就OK了,不需要去理解Maven的那些概念,而这篇文章就是要教会你会使用Maven,而整个系列则是要让你明白整个Maven。这篇文章就是如此,仅仅就是告诉你怎么用Maven,仅此而已,会用是学习整个系列的前提。 编写POM就像composer的composer.json、Make的makefile文件一样,Maven项目的核心是pom.xml文件。POM(Project Object Model,项目对象模型)定义了项目的基本信息,用于描述项目如何构建,声明项目依赖,等等。 现在我们不借助任何其它命令和IDE,来创建一个Maven项目。 首先,编写pom.xml文件。还是按照老规矩,从一个Hello World项目进行演示。以下就是创建项目的POM文件。 <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.jellythink.HelloWorld</groupId> <artifactId>hello-world</artifactId> <version>1.0-SNAPSHOT</version> <name>hello-world</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties></project>对于POM文件,现在细说一下。 代码的第一行是XML头,指定了该xml文档的版本和编码方式。紧接着是project元素,project是所有pom.xml的根元素,它还声明了一些POM相关的命名空间及xsd元素;根元素下的第一个子元素modelVersion指定了当前POM模型的版本,对于Maven 2和Maven 3来说,它只能是4.0.0;接下来就是groupId、artifactId和version了,这三个是上述代码三个元素。这三个元素定义了一个项目的基本坐标,在Maven的世界里,所有的jar和war都是基于坐标进行区分的,会面的文章还会细说坐标;groupId定义了项目属于哪个组,这个组往往和项目所在的组织或公司存在关联,一般是使用组织或公司的域名;比如上面的groupId是com.jellythink.HelloWorld,其中com.jellythink就是我的网站域名倒过来写的,而HelloWorld则是整个项目的名称;artifactId定义了当前Maven项目在组中唯一的ID,一般一个大项目组下面可能会包含多个子项目或子模块,而这个artifactId就是子项目或者子模块的名称;version指定了这个项目当前的版本,后面的文章还会细说Maven中版本的含义;name元素声明了一个对于用户更为友好的项目名称,方便后期的管理;properties指定了Maven的一些重要属性,后续还会重点说这个属性的一些配置。创建完pom.xml文件后,接下来就是创建代码文件了。在Maven中,有这样的一个约定,项目主代码都位于src/main/java目录,项目测试代码都位于src/test/java目录;接下来我们先按照这个约定分别创建目录,然后在代码目录创建com/jellythink/HelloWorld/App.java文件;在测试目录创建com/jellythink/HelloWorld/AppTest.java文件。 还是老规矩,我们在App.java中打印Hello World!,代码如下: public class App { public String sayHello() { return "Hello World"; } public static void main( String[] args ) { System.out.println(new App().sayHello()); }}同理,对于AppTest.java中编写以下单元测试代码: public class AppTest { @Test public void testSayHello() { App app = new App(); String result = app.sayHello(); assertEquals("Hello World", result); }}在Java中,我们进行单元测试时,基本上都是使用的JUnit,要使用JUnit这个包,我们就需要引入这个依赖包,此时,我们就需要在pom.xml中添加以下依赖内容: ...

October 6, 2019 · 1 min · jiezi

Maven基础教程之坐标

这又是一个系列,一个要把Maven讲透的系列,希望能够对大家有帮助!前言看完上一篇《Maven基础教程之使用入门》后,大家基本上就会使用Maven了,但是Maven远不止上一篇文章中总结的那么一点东西,还有很多其他非常重要的概念,而这些概念就是我们深入理解Maven,学习Maven原理的重点,从这一篇文章开始,我将开始重点总结Maven中的一些重点概念和原理性的东西,通过这些重要的概念和原理性的东西,让大家知其然,也知其所以然。 Maven坐标是什么?在初中的数学几何中,我们知道,平面中任何一个坐标都可以唯一标识该平面中的一个点。对于Maven世界中,有数量巨大的JAR包或者WAR包,在还没有坐标这个概念前,我们是如何引入我们项目需要的依赖呢?比如我现在创建了一个Spring的项目,此时我就要去Spring官网下载Spring相关的JAR包,放到我的项目Classpath下面去;当需要Mybatis相关的JAR包时,我再去Mybatis的官网下载对应的JAR包,再放到Classpath中去。也就是说,我们缺少什么JAR包,就去网上下载对应的JAR包,而很多时候,我们只有在编译出现错误时,我们才知道我们到底缺了哪些依赖的JAR包,所以这样的工作就让我们很被动,同时又没法进行流程自动化。 问题抛出来了,我们要相信这个世界上大牛的能力,没有解决不了的问题。基于这些难题,Maven就定义了这样一组规则来搞定它。 世界上任何一个JAR包或者WAR包都可以使用Maven坐标唯一标识,Maven坐标的元素包括groupId、artifactId、version和classifier等。只要我们提供了正确的坐标元素,Maven就能找到对应的JAR包或者WAR包。就是这么简单的。所以,在我们开发自己的项目时,Maven也强制要求我们需要为项目指定适当的坐标,这样其它的Maven项目才能引用对应项目生成的JAR包或者WAR包。 细说Maven坐标Maven坐标就是定义了一种规则,任何基于Maven开发的项目都需要遵守这个规则,也就是需要明确定义自己的坐标,我们可以看一下上一篇文章中pom.xml文件里的那个示例: <groupId>com.jellythink.HelloWorld</groupId><artifactId>hello-world</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging>上面代码中,关于坐标的各个坐标元素,这里重点说明一下: groupId:定义当前Maven项目隶属的实际项目;我们要明白的是Maven项目和实际项目不一定是一对一的关系。举一个最常见的例子,比如Spring Framework这个实际项目,其对应的Maven项目会有很多,如spring-core、spring-context等。这是由于Maven中模块的概念,因此实际项目往往会被划分成很多模块。当我们看到一个项目的groupId时,会觉的很熟悉,为什么?是不是和我们经常定义的Java包名很像,这个和我们在Java中定义顶级包名的规则是一样的,通常与公司或者组织的域名反向一一对应。artifactId:该元素定义实际项目中的一个Maven项目(模块),一般推荐的做法是使用实际项目名称作为artifactId的前缀,比如spring-core的前缀是spring一样。version:该元素定义Maven项目当前所处的版本;在Maven中定义了一整套完整的版本定义规范,后续会有专门的文章进行总结。packaging:该元素定义Maven项目的打包方式;打包方式通常与所编译生成的文件扩展名对应,但也不是绝对的,比如packaging为maven-plugin的构件扩展名为jar;packaging常见的是jar和war这两种类型;不同的打包方式会影响到构建的生命周期。很多时候,我们也会看到我们没有定义这个packaging元素,此时Maven会使用默认值jar。classifier:该元素用来帮助定义输出一些附属文件。附属输出文件与主输出文件是对应的,比如上面的主输出文件是hello-world-1.0-SNAPSHOT.jar,该项目可能还会通过使用一些插件生成如hello-world-1.0-SNAPSHOT-javadoc.jar、hello-world-1.0-SNAPSHOT-sources.jar这样的一些附属输出文件。需要我们注意的是,不能直接定义项目的classifier,因为附属输出文件不是项目直接默认生成的,而是由附加的插件帮助生成的。总结到这里,关于Maven坐标的相关知识就整理完了,回过头来看,你会发现Maven中的坐标是一个非常好理解,但是却又非常重要,非常基础的一个概念。不懂这个坐标的概念,可能最后连pom.xml文件都看不懂,再往下的学习也就都是白搭,最后,庆幸的是这个还不是很难学习,至少看懂我这里总结的应该木有问题;不过能看懂我这里总结的,也就OK了。 2019年4月3日,于内蒙古呼和浩特。

October 6, 2019 · 1 min · jiezi

Maven基础教程之安装与配置

这又是一个系列,一个要把Maven讲透的系列,希望能够对大家有帮助!前言至于为什么要写Maven这个系列呢?其实我自己还是感慨颇深的,在去年一年的工作中,接触了一帮出差过来支撑的兄弟,但是这帮兄弟也都是刚走出校门的,或者从其它行业转过来做开发的,经验都很少,基础的Maven都不会配置,更不要说Maven的那些概念了。其实,在我们周围很多的看似很厉害的“大牛”,他能和你侃侃而谈,从人工智能到大数据,从大数据到区块链等等,他们都能说出一二,但是一到落实的实处时,比如让他们“show me your code”的时候,他们总是很痛苦的,或者是漏洞百出的。所以,这个系列一来为需要补充Maven基础知识的兄弟提供一个捷径;二来总结一下自己Maven知识,以免像那些“大牛”一样。 Windows上安装Maven首先我们需要知道的事情是Maven是依赖JDK的,所以不管是在Windows还是Linux,需要使用Maven,就必须要先安装JDK。每个版本Maven对JDK的版本要去都不一致,我们可以去Maven的官网下载页,可以看到Maven的安装要求。 对于Windows的安装来说,我们直接下载对应的安装包即可。关于Windows上安装Maven不是这篇文章的重点,我这里也就一笔带过,推荐网上的一篇教程吧。具体的安装步骤可以看这篇《Maven在Windows上的安装与配置》。 Linux上安装Maven从Maven的官网下载安装包以后,进行解压。解压后得到apache-maven-3.6.0这个包;然后执行ln -s apache-maven-3.6.0 maven命令创建一个软链接,然后在系统环境变量PATH中添加以下环境变量: export M2_HOME=~/mavenexport PATH=$PATH:$M2_HOME/bin检查Maven是否安装成功,只需要输入mvn -v,如果输出如下图所示,就是安装成功了。 肯定就有小伙伴会问了,为什么要创建一个软链接。其实在Linux上安装软件包,我都有一个习惯,应该是我们整个公司也都是这样要求的。安装软件包时,会在安装目录旁平行的创建一个符号链接,以方便将来升级;以后Maven升级时,只需要下载新版本的Maven包,解压放在平行目录,然后修改这个链接就可以了。 Maven安装目录分析M2_HOME环境变量指向Maven的安装目录。我们可以看到Maven安装目录下有以下文件和文件夹: conf:该目录包含了一个非常重要的文件settings.xml。直接修改该文件,就能在机器上全局地定制Maven的行为。而一般情况下,我们都会复制该文件至~/.m2目录下,然后修改该文件,在用户范围定制Maven的行为;bin:该目录包含了mvn运行的脚本,这些脚本用来配置Java命令,配置好classpath和相关的Java系统属性,然后运行执行Java命令。该目录除了包含Unix和Windows平台运行的脚本外,还包含一个m2.conf文件,这是classworlds的配置文件,后续还会细说;boot:该目录下只有一个plexus-classworlds-2.5.2.jar文件,plexus-classworlds是一个类加载器框架,相对于默认的Java类加载器,它提供了个更丰富的语法以方便配置,Maven使用该框架加载自己的类库;lib:该目录包含了所有Maven运行时需要的Java类库,Maven是分模块开发的,所以这里有多个Jar包。NOTICE:记录了Maven包含的第三方软件;LICENSE:记录了Maven使用的软件许可证;README.txt:记录了Maven的简要介绍,包含安装需求及如何安装的简要命令等。Maven安装最佳实践最佳实践一:设置MAVEN_OPTS环境变量运行mvn命令实际上是执行了Java命令,既然是运行Java,那么运行Java命令可用的参数当然也应该在运行mvn命令时可用。通常需要设置MAVEN_OPTS的值为-Xms128m -Xmx512m,因为Java默认的最大可用内存往往不能够满足Maven运行的需要。我们一般把MAVEN_OPTS设置成环境变量。 最佳实践二:配置用户范围settings.xmlMaven用户可以选择配置M2_HOME/conf/settings.xml或者~/.m2/settings.xml。前者是全局范围的,整个机器上的所有用户都会直接受到该配置的影响,而后者是用户范围的,只有当前用户才会受到该配置的影响。我们在配置时,都是使用用户范围的settings.xml,主要是为了避免无意识的修改影响到系统中其它用户;如果有需求,需要统一系统中所有用户的settings.xml配置,这样就可以全局范围的settings.xml。 除了影响范围这个因素,配置用户范围settings.xml文件还便于Maven升级。直接修改conf目录下的settings.xml会导致Maven升级不便,每次升级到新版本的Maven,都需要复制settings.xml文件。如果使用~/.m2目录下的settings.xml,就不会影响到Maven安装文件,升级时就不需要触动settings.xml文件。 总结这是一篇特别基础的Maven安装教程,对于Maven的入门有一定的帮助,希望大家能通过我的整个系列可以入门Maven,丰富自己的工具库。 2019年3月23日,于内蒙古呼和浩特。

October 6, 2019 · 1 min · jiezi

Maven基础教程之Archetype

这又是一个系列,一个要把Maven讲透的系列,希望能够对大家有帮助!前言作为整个系列的最后一篇,写到这个时候,多多少少都会有一点惰性,在4月初定计划时,原计划用一个月的时间把整个Maven系列整理完,但是这都到了5月份了,罪过、罪过! 虽然作为整个系列的最后一篇文章,我也是丝毫不敢有所懈怠,仍要认真的来总结一番。 Archetype是什么?在《Maven基础教程之使用入门》这篇文章中,就有说到Archetype,但是在那篇文章中并没有细说。其实,我们可以将Archetype理解成Maven项目的模板,通过Archetype,我们可以快速生成项目框架。阅读过之前的文章的小伙伴,肯定也就知道了,整个Maven的具体功能都是通过插件来完成的;同理,Archetype也是通过插件来完成的。这个名为maven-archetype-plugin的插件提供了Archetype的所有功能。由于Archetype使用范围非常广,在很多有名的IDE中都集成了Archetype特性,以方便我们快速的创建Maven项目。下图就是IDEA创建Maven项目时继承的Archetype: 如何使用Archetype关于Archetype,Maven 2和Maven 3有很大的区别,考虑到咱们现在基本上都是使用的Maven 3,所以这里就重点总结Maven 3中Archetype的使用。 我们在命令行输入mvn archetype:generate后,Archetype插件会输出一个Archetype列表供我们选择,我们根据我们的需要选择不同的Archetype模板,然后根据提示,输入groupId、artifactId、version等必要的信息,就可以创建不同的Maven项目。虽然不是非常友好的UI界面,但是使用起来也是非常简单的。 由于Archetype列表比较多,我们在选择的时候难免就会出现选择恐惧症,所以,对于一些常用的Archetype,大家需要有所熟悉,对于一些常用的Archetype,这里推荐一篇博文和大家分享——《Maven 三种archetype说明》。 总结其实对于Archetype,我们只需要明白这是一个脚手架就OK了,更深的东西,比如如何编写符合我们自己要求的Archetype啊,我这里没有涉及,因为考虑到99%的情况下,我们不会涉及这个的,现有的Archetype也基本上都满足我们的日常开发需要了。所以,那就这样吧,这个系列圆满结束! 果冻想,玩技术,玩代码! 2019年5月5日,于内蒙古呼和浩特。

October 6, 2019 · 1 min · jiezi

Maven基础教程之测试

这又是一个系列,一个要把Maven讲透的系列,希望能够对大家有帮助!前言关于使用Maven进行测试,我本来是不想总结的,然后考虑到这个功能在实际开发中还经常使用,或者说,有的同学毕业后得第一份正式工作就是搞测试,编码写测试用例(其实我就是这样的)。所以,结合我自身的工作经历来看,我个人是非常崇尚测试,重视测试的,所以,这里我再通过这篇文章,对Maven是如何集成测试的进行简单的总结,方便大家有一个整体的印象和大的概念。 maven-surefire-plugin简介通过之前的学习,我们都知道Maven本身并不是一个单元测试框架,在Java中,主流的单元测试框架是JUnit和TestNG。而Maven所做的只是在构建执行到特定生命周期阶段的时候,通过插件来执行JUnit或者TestNG的测试用例。而这一常用的插件就是maven-surefire-plugin。 在默认情况下,maven-surefire-plugin的test目标会自动执行测试源码路径下所有符合一组命名模式的测试类。这组模式为: **/Test*.java:任何子目录下所有命名以Test开头的Java类**/*Test.java:任何子目录下所有命名以Test结尾的Java类**/*TestCase.java:任何子目录下所有命名以TestCase结尾的Java类只要将测试类按照上述模式命名,Maven就能自动运行它们,用户也就不再需要定义聚合测试用例。 为了能够运行测试,Maven需要在项目中引入测试框架的依赖,在前面的文章都有说到,这里就不再总结。 跳过测试有的时候,我说的是有些时候哈,为了更快的完成构建,我们会跳过费时的测试阶段,这个时候,我们只需要在执行mvn命令时加上skipTests参数即可,比如这样: mvn clean package -DskipTests或者,我们也可以在POM中对插件进行配置,比如这样: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.12.4</version> <configuration> <skipTests>true</skipTests> </configuration></plugin>动态指定要运行的测试用例上面直接跳过全部测试,这样的确有点极端,很多时候,我们增加了一个测试类,为了节省时间,就不想将所有的测试用例都运行一篇,而只是将新增的测试类运行一遍就OK了,这个时候我们就需要动态指定要运行的测试用例。 maven-surefire-plugin提供了一个test参数让Maven用户能够在命令行指定要运行的测试用例。比如这样: mvn test -Dtest=LoginTest这里test参数的值是测试用例的类名,这行命令的效果就是只有LoginTest这一个测试类得到运行。当然了,maven-surefire-plugin的test参数还支持一些高级的赋值模式,比如这样: mvn test -Dtest=Admin*Test星号可以匹配零个或多个字符,上述命令会运行项目中所有类名以Admin开头、Test结尾的测试类。除了星号匹配,还可以使用逗号指定多个测试用例: mvn test -Dtest=LoginTest,AdminSearchTest包含与排除测试用例通过命令行动态指定要运行的测试用例确实不错,但是如果要动态指定运行的测试用例比较多时,通过命令就比较麻烦;换一种方式来思考,那就是如何排除指定的测试用例呢? <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.12.4</version> <configuration> <excludes> <exclude>**/LoginTest.java</exclude> <exclude>**/Admin*Test.java</exclude> </excludes> </configuration></plugin>有了上面所示的excludes配置后,maven-surefire-plugin就不再自动运行它们了。 测试报告在我以前的东家,如果需要安排系统上线,就必须要提交系统测试报告。而通过maven-surefire-plugin插件,就可以生成简单明了的系统测试报告。默认情况下,maven-surefire-plugin会在项目的target/surefire-reports目录下生成两种格式的错误报告: 简单文本格式简单的文本格式信息如下: -------------------------------------------------------------------------------Test set: com.jellythink.HelloWorld.AppTest-------------------------------------------------------------------------------Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.047 sec与JUnit兼容的XML格式XML格式的测试报告主要是为了支持工具的解析。上面就看个人项目的需要了,按照需要生成即可,非常的方便。 总结这篇文章主要总结了Maven中的测试,具体的就是围绕着maven-surefire-plugin这个官方默认插件进行的总结。这里总结的测试,在你将来的职业生涯中不一定会遇到或者使用到,但是至少我这里总结的内容会对你以后的工作可以提供一点点的指点,那就足够了! 果冻想,玩代码,玩即使! 2019年4月28日,于内蒙古呼和浩特。

October 6, 2019 · 1 min · jiezi

Maven基础教程之生命周期

这又是一个系列,一个要把Maven讲透的系列,希望能够对大家有帮助!前言在Maven中,核心概念一共有五个,包括前面已经总结完成的坐标、依赖和仓库,以及这里要讲的生命周期,还有将在下一篇要讲的插件。掌握了这五个核心概念,也就基本上把握了Maven的命脉。不夸张的说,把握了这五大核心概念,你可以自豪的说你在Maven的掌握上,超过了80%的人。而除了这五大概念,我总结的其它Maven系列的文章,无法就是Maven的具体场景应用,大体上都离不开这五大核心概念。 废话不多说,开始总结今天的总结! Maven生命周期是什么?人生老病死,这是一个生命周期。在Maven中,也有一个生命周期的概念。不管是刚刚入门的开发菜鸟,还是做了多年开发的大佬,每天干的工作无非就是对自己负责的项目进行清理、编译、测试和部署。虽然大家每天都在做这些工作,但是公司和公司之间、项目与项目之间,往往使用不同的方式做这些工作。有的是手工来搞定这些,有的人可能会聪明一些,写一些自动化脚本来搞定这些。不管大家怎么搞,都是能满足自己当下的工作需要,很好的完成自己当下的工作。可能换了个公司,或者换了个项目,把自己之前写的脚本,改吧改吧,接着来。你改吧改吧,能用就好,无可厚非,但是的确很麻烦,搞不好改了半天,发现之前的脚本不好用,可能还要重写。是的,你的痛点问题,Maven也知道,Maven说了,它来帮你搞定这些问题。所以就提出了Maven生命周期的概念。 Maven生命周期就是为了对所有的构建过程进行抽象和统一,开发了一套高度完善的、易扩展的生命周期。这个生命周期包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有构建步骤。换句话说,几乎所有项目的构建,都能映射到这样一个生命周期上。 Maven的生命周期是抽象的,也就是说生命周期本身不做任何实际的工作,在Maven的设计中,实际的任务都交给插件来完成。这种思想与设计模式中的模板方法非常相似。对模板方法设计模式不清楚的伙计可以看这里。Maven采用这样的设计,既保证了Maven整体框架的轻便,也最大程度的扩展性。 Maven生命周期抽象了构建的各个步骤,明确了它们的逻辑次序,但没有提供具体的实现。Maven通过插件机制,这些插件来完成实际的工作,同时每个构建步骤都可以绑定一个或者多个插件行为。为了让Maven开箱即用,Maven为大多数构建步骤编写并绑定了默认插件。比如针对编译的插件有maven-compiler-plugin,针对测试的插件有maven-surefire-plugin等。虽然在大多数时间里,用户几乎都不会感觉到插件的存在,而Maven如此的强大,都是因为在幕后有功能强大的插件,这一切实际的工作都是由这些插件来完成的。 通过Maven定义的生命周期和插件机制保证了所有Maven项目有一致的构建标准,简化了项目的构建工作。 详解Maven生命周期在Maven中,有三套相互独立的生命周期,分别是clean、default和site。 clean:clean生命周期的目的是清理项目;default:default生命周期的目的是构建项目;site:site生命周期的目的是建立项目站点。每个生命周期包含一些阶段(phase),这些阶段是有顺序的,并且后面的阶段依赖于前面的阶段。我们和Maven最直接的交互方式就是通过调用这些生命周期阶段。以clean生命周期为例,它包含的阶段有pre-clean、clean和post-clean。当我们调用pre-clean的时候,只有pre-clean阶段后执行;当我们调用clean的时候,pre-clean和clean阶段会按顺序执行;当我们调用post-clean的时候,pre-clean、clean和post-clean都会按顺序执行。 和生命周期阶段的前后依赖关系相比,clean、default和site这三套生命周期本身是相互独立的,我们可以仅仅调用clean生命周期的某个阶段,或者仅仅调用default生命周期的某个阶段,而不会对其它生命周期产生任何影响。 常用命令详解在《Maven基础教程之使用入门》这篇文章中,讲到了一些通过命令行来编译、测试和打包程序的命令,现在总结完了生命周期,再回过头去看这些命令,你将会有更深刻的认识。 mvn clean:调用实际插件完成clean生命周期的clean阶段的操作,实际调用的是pre-clean和clean两个阶段;mvn test :调用default生命周期对应的阶段的插件,完成从validate到test阶段的所有操作;mvn clean install:调用clean周期的clean阶段和default的install阶段,实际调用的是pre-clean、clean以及validate到install阶段;mvn clean deploy site-deploy:调用完整的三个生命周期所有阶段(post-clean不被调用)。总结理论性的东西还是蛮多的,而这些知识点是我们后续用好Maven的基础,希望大家通过这里总结的内容,能对Maven中的生命周期这个重要概念有所理解。下一篇将重点总结插件,下一篇再见。 果冻想,玩代码,玩技术! 2019年4月14日,于内蒙古呼和浩特。

October 6, 2019 · 1 min · jiezi

Maven基础教程之聚合

这又是一个系列,一个要把Maven讲透的系列,希望能够对大家有帮助!前言通过前面几篇文章,我把Maven中的坐标、仓库、依赖、生命周期和插件这五大核心概念进行了总结,掌握了这五大核心概念,基本上也就把住了Maven的脉。从这篇文章开始,我们将从实际的应用场景出发,总结Maven的一些比较常见的用户,通过这些常见的用户来更好的把握Maven,学习Maven。 我们的需求在前后台分离,微服务大行其道的今天,我们的应用不再是一个超级大的包了,而是分成了多个子项目模块,每个子项目模块都是一个单独的工程项目。这就出现应用多的情况,此时如果你负责一个功能开发时,需要修改多个子项目模块时,就需要去修改不同的工程项目,当你开发完进行联调时,就需要一次构建多个工程项目,当出现问题时,又可能同时修改多个工程项目,此时你是一个一个工程项目的去构建呢?还是希望有一种办法一次性可以构建多个工程项目。 当然了,我们肯定希望存在一种办法,我们通过点击某个按钮就可以开始构建多个工程项目,然后我们去喝杯咖啡的。那我们的这种需求在Maven中是否能实现呢?毫无疑问,Maven是可以搞定这个问题的,这就是Maven中的聚合,通过聚合我们就可以解决这个痛点问题。下面我就通过实际的项目来说说Maven中的聚合到底是个什么鬼。 聚合实战现在我准备了两个基于Maven的子工程项目,分别是Project-A和Project-B。这两个项目都可以单独编译,单独构建。但是为了能够使用一条命令就可以构建Project-A和Project-B这两个子工程项目,我们需要创建一个额外的名为Project-Aggregator的工程项目,然后通过该模块构建整个项目的所有模块。由于这个Project-Aggregator的工程项目是一个聚合项目,它是不需要src和test目录的,只需要有一个POM就OK了,下面就是这个Project-Aggregator工程项目的POM文件内容: <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.jellythink.AggregatorDemo</groupId> <artifactId>Project-Aggregator</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <name>Project-Aggregator</name> <modules> <module>../Project-A</module> <module>../Project-B</module> </modules></project>接下来,我们在Project-Aggregator工程项目目录下执行mvn clean package命令,就会看到以下输出: [INFO] Scanning for projects...[INFO] ------------------------------------------------------------------------[INFO] Reactor Build Order:[INFO][INFO] Project-A[INFO] Project-B[INFO] Project-Aggregator[INFO][INFO] ------------------------------------------------------------------------[INFO] Building Project-A 1.0-SNAPSHOT[INFO] ------------------------------------------------------------------------[INFO][INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ Project-A ---[INFO] Deleting E:\Code\Spring\Project-A\target[INFO][INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ Project-A ---[INFO] Using 'UTF-8' encoding to copy filtered resources.[INFO] skip non existing resourceDirectory E:\Code\Spring\Project-A\src\main\resources[INFO][INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ Project-A ---[INFO] Changes detected - recompiling the module![INFO] Compiling 1 source file to E:\Code\Spring\Project-A\target\classes[INFO][INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ Project-A ---[INFO] Using 'UTF-8' encoding to copy filtered resources.[INFO] skip non existing resourceDirectory E:\Code\Spring\Project-A\src\test\resources[INFO][INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ Project-A ---[INFO] Changes detected - recompiling the module![INFO] Compiling 1 source file to E:\Code\Spring\Project-A\target\test-classes[INFO][INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ Project-A ---[INFO][INFO] -------------------------------------------------------[INFO] T E S T S[INFO] -------------------------------------------------------[INFO] Running com.jellythink.AggregatorDemo.AppTest[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.032 s - in com.jellythink.AggregatorDemo.AppTest[INFO][INFO] Results:[INFO][INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0[INFO][INFO][INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ Project-A ---[INFO] Building jar: E:\Code\Spring\Project-A\target\Project-A-1.0-SNAPSHOT.jar[INFO][INFO] ------------------------------------------------------------------------[INFO] Building Project-B 1.0-SNAPSHOT[INFO] ------------------------------------------------------------------------[INFO][INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ Project-B ---[INFO] Deleting E:\Code\Spring\Project-B\target[INFO][INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ Project-B ---[INFO] Using 'UTF-8' encoding to copy filtered resources.[INFO] skip non existing resourceDirectory E:\Code\Spring\Project-B\src\main\resources[INFO][INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ Project-B ---[INFO] Changes detected - recompiling the module![INFO] Compiling 1 source file to E:\Code\Spring\Project-B\target\classes[INFO][INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ Project-B ---[INFO] Using 'UTF-8' encoding to copy filtered resources.[INFO] skip non existing resourceDirectory E:\Code\Spring\Project-B\src\test\resources[INFO][INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ Project-B ---[INFO] Changes detected - recompiling the module![INFO] Compiling 1 source file to E:\Code\Spring\Project-B\target\test-classes[INFO][INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ Project-B ---[INFO][INFO] -------------------------------------------------------[INFO] T E S T S[INFO] -------------------------------------------------------[INFO] Running com.jellythink.AggregatorDemo.AppTest[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.046 s - in com.jellythink.AggregatorDemo.AppTest[INFO][INFO] Results:[INFO][INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0[INFO][INFO][INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ Project-B ---[INFO] Building jar: E:\Code\Spring\Project-B\target\Project-B-1.0-SNAPSHOT.jar[INFO][INFO] ------------------------------------------------------------------------[INFO] Building Project-Aggregator 1.0-SNAPSHOT[INFO] ------------------------------------------------------------------------[INFO][INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ Project-Aggregator ---[INFO] ------------------------------------------------------------------------[INFO] Reactor Summary:[INFO][INFO] Project-A .......................................... SUCCESS [ 3.513 s][INFO] Project-B .......................................... SUCCESS [ 1.424 s][INFO] Project-Aggregator ................................. SUCCESS [ 0.047 s][INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------[INFO] Total time: 5.093 s[INFO] Finished at: 2019-04-22T21:54:08+08:00[INFO] Final Memory: 19M/274M[INFO] ------------------------------------------------------------------------从输出可以看到,我们在构建Project-Aggregator项目时,Project-A和Project-B就会一同被构建,在存在多个项目时,这是非常方便的。 ...

October 6, 2019 · 2 min · jiezi

Maven基础教程之多环境构建

这又是一个系列,一个要把Maven讲透的系列,希望能够对大家有帮助!前言这篇文章总结的多环境构建绝对是会在实际工作中会用到的内容。比如我现在的这家公司的Maven项目,基本上都使用了这篇文章将要总结的多环境构建。那到底什么是多环境构建呢? 我们想象一下这样的一个场景。一般我们的项目都会有开发环境、测试环境和生产环境,这些环境的数据库等配置基本上都是不一样的,那么我们在进行项目构建的时候就需要能够识别所在的环境并使用正确的配置数据。对于多个环境,我们如何能够灵活的使用不同的配置数据呢? 在Maven中,为了灵活的支持这种场景,内置了三大特性,即属性、Profile和资源过滤。下面我们将通过具体的代码示例来细说这三大特性。 Maven属性对于Maven属性,在前面的文章我们也接触过,比如之前是这样用的: <project> <modelVersion>4.0.0</modelVersion> <groupId>com.jellythink.BookStore</groupId> <artifactId>project-A</artifactId> <version>1.0.0</version> <properties> <springframework.version>5.1.6.RELEASE</springframework.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${springframework.version}</version> </dependency> </dependencies></project>通过<properties>元素,我们可以自定义一个或多个Maven属性,然后在POM的其它地方使用${属性名称}的方式引用该属性,这种做法的最大意义在于消除重复,便于后期统一修改。但是这不是Maven属性的全部,实际上,在Maven中包含以下六类属性: 内置属性主要有以下两个常用内置属性: ${basedir}表示项目根目录,即包含pom.xml文件的目录${version}表示项目版本POM属性我们可以使用POM属性引用POM文件中对应元素的值,比如${project.artifactId}就对应了<project><artifactId>元素的值,常用的POM属性包括: ${project.build.sourceDirectory}:项目的主源码目录,默认为src/main/java/${project.build.testSourceDirectory}:项目的测试源码目录,默认为src/test/java/${project.build.directory}:项目构建输出目录,默认为target/${project.outputDirectory}:项目主代码编译输出目录,默认为target/classes/${project.testOutputDirectory}:项目测试代码编译输出目录,默认为target/test-classes/${project.groupId}:项目的groupId${project.artifactId}:项目的artifactId${project.version}:项目的version,与${version}等价${project.build.finalName}:项目打包输出文件的名称,默认为${project.artifactId}-${project.version}这些属性都对应一个POM元素,有一些属性的默认值都是在超级POM中定义的。自定义属性自定义属性就是通过<properties>元素定义的属性,最开始的例子就已经讲的很明白了。Settings属性大家还记得Maven中的settings.xml文件吗?不记得的伙伴可以去看下这篇《Maven基础教程之安装与配置》。而这个Settings属性就表示我们可以使用以settings.开头的属性引用settings.xml文件中XML元素的值,比如我们可以使用${settings.localRepository}来引用用户本地仓库的地址。Java系统属性所有的Java系统属性都可以使用Maven属性引用,比如${user.home}指向用户的目录。我们可以使用mvn help:system查看所有的Java系统属性。环境变量属性所有环境变量都可以使用以env.开头的Maven属性引用。比如${env.JAVA_HOME}指向了JAVA_HOME环境变量的值。我们可以使用mvn help:system查看所有的Java系统属性。正确的使用这些Maven属性可以帮助我们简化POM的配置和维护工作。 资源过滤在我们开发过程中,经常会碰到这样的配置文件: database.jdbc.driverClass = com.mysql.jdbc.driverClassdatabase.jdbc.connectionURL = jdbc:mysql://localhost:3306/devdatabase.jdbc.username = developdatabase.jdbc.password = develop-password上面的配置数据只是对开发人员的,如果测试人员进行时,则使用的如下这样的一套配置文件: database.jdbc.driverClass = com.mysql.jdbc.driverClassdatabase.jdbc.connectionURL = jdbc:mysql://localhost:3306/testdatabase.jdbc.username = testdatabase.jdbc.password = test-password也就是说,在开发环境和测试环境,我们需要使用不同的配置文件,在没有使用Maven之前,我们都是手动的修改对应的配置数据,话又说回来了,这样很麻烦,还很容易出错。现在有了Maven,我们需要作出一点改变。 为了应对不同的使用环境,我们需要将配置文件中变化的部分使用Maven属性替换,比如上面的配置文件,我们需要修改成这个样子: database.jdbc.driverClass = ${db.driver}database.jdbc.connectionURL = ${db.url}database.jdbc.username = ${db.username}database.jdbc.password = ${db.password}我们在配置文件中定义了四个Maven属性:db.driver、db.url、db.username和db.password。接下来,我们就需要在某个地方定义这些属性。在Maven中,我们只需要使用一个额外的profile来定义这些属性就可以了。 <profiles> <profile> <id>dev</id> <properties> <db.driver>com.mysql.jdbc.driverClass</db.driver> <db.url>jdbc:mysql://localhost:3306/dev</db.url> <db.username>develop</db.username> <db.password>develop-password</db.password> </properties> </profile></profiles>这里通过profile定义了这些属性,并使用了一个id为dev的值来区别这个profile,这样以后我们就可以针对不同的环境定义不同的profile,就可以非常的灵活。 有了属性定义,配置文件中也使用了这些属性,这样就可以了吗?不是这么简单的!我们都知道,Maven属性默认只有在POM中才会被解析。也就是说,${db.username}放到POM中会被解析成develop,但是如果放到src/main/resources/目录下的文件中,构建的时候它还是${db.username}。所以,我们需要让Maven解析资源文件中的Maven属性。 资源文件的处理其实是maven-resources-plugin的工作,但是它默认的行为只是将项目主资源文件复制到主代码编译输出目录中,将测试资源文件复制到测试代码编译输出目录中。我们只需要开启资源过滤,这个插件就能够解析资源文件中的Maven属性。 为主资源目录开启过滤: ...

October 6, 2019 · 1 min · jiezi

Maven基础教程之继承

这又是一个系列,一个要把Maven讲透的系列,希望能够对大家有帮助!前言上一篇文章就聚合进行了详细的总结,通过聚合,解决了我们构建多个项目的繁琐问题。但是,通过总结上一篇文章,大家可能会发现这么个问题,Project-A和Project-B项目的POM文件,有很多相同的部分。通过以往的开发经验,如果多个模块有相同的部分,那就意味着我们可以把相同的部分抽取出来,作为公共的部分进行使用,比如在Java中,我们可以把相同的部分放在父类中,子类继承父类,就搞定了。在Maven的世界里,也有类似的机制能让我们提取出重复的配置,这就是POM的继承,而这篇文章就对Maven中的POM继承进行详细的总结。 小试牛刀这里我还是将通过一个例子来了解一下Maven继承的初步使用配置。还是使用三个工程项目Project-Parent、Project-C和Project-D来进行说明,三个项目关系如下: Project-Parent工程POM文件如下: <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.jellythink.ExtendDemo</groupId> <artifactId>Project-Parent</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <name>Project-Parent</name></project>看这个POM文件,会发现和聚合有几分相像,只是没有modules节点,同样需要注意的是packaging的取值,必须使用pom。 Project-C的POM文件如下: <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.jellythink.ExtendDemo</groupId> <artifactId>Project-Parent</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../Project-Parent/pom.xml</relativePath> </parent> <artifactId>Project-C</artifactId> <name>Project-C</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.1.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.1.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.1.6.RELEASE</version> </dependency> </dependencies></project>Project-D的POM文件如下: <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.jellythink.ExtendDemo</groupId> <artifactId>Project-Parent</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../Project-Parent/pom.xml</relativePath> </parent> <artifactId>Project-D</artifactId> <name>Project-D</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.1.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.1.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.1.6.RELEASE</version> </dependency> </dependencies></project>在Project-C和Project-D工程中都使用了parent元素声明父模块,parent下的坐标元素groupId、artifactId和version是必须的,它们指定了父模块的坐标;元素relativePath表示父模块POM的相对路径。在项目构建时,Maven会首先根据relativePath检查父POM。 ...

October 6, 2019 · 1 min · jiezi

Spring-Boot集成smartdoc生成api文档

smart-doc是一个java restful api文档生成工具,smart-doc颠覆了传统类似swagger这种大量采用注解侵入来生成文档的实现方法。smart-doc完全基于接口源码分析来生成接口文档,完全做到零注解侵入,你只需要按照java标准注释的写,smart-doc就能帮你生成一个简易明了的markdown或是一个像GitBook样式的静态html文档。下面将介绍如何在Spring Boot项目中集成smart-doc生成一个简明的api文档。 注意: smart-doc已经被开源中国收录,并且开始被国内很多开发者使用到自己项目中快速生成接口文档。 smart-doc功能零注解、零学习成本、只需要写标准java注释。基于源代码接口定义自动推导,强大的返回结构推导。支持Spring MVC,Spring Boot,Spring Boot Web Flux(controller书写方式)。支持Callable,Future,CompletableFuture等异步接口返回的推导。支持JavaBean上的JSR303参数校验规范。对json请求参数的接口能够自动生成模拟json参数。对一些常用字段定义能够生成有效的模拟值。支持生成json返回值示例。支持从项目外部加载源代码来生成字段注释(包括标准规范发布的jar包)。支持生成多种格式文档:Markdown、HTML5、Asciidoctor。轻易实现在Spring Boot服务上在线查看静态HTML5 api文档。开放文档数据,可自由实现接入文档管理系统。在Spring Boot项目中集成Smart-doc添加smart-doc依赖,注意打包后不需要将smart-doc打入最终的产品包,因此我推荐只用test级别就可以了。 <dependency> <groupId>com.github.shalousun</groupId> <artifactId>smart-doc</artifactId> <version>1.7.0</version> <scope>test</scope></dependency>新建一个对象: public class User { /** * 用户名 */ private String userName; /** * 昵称 */ private String nickName; /** * 用户地址 */ private String userAddress; /** * 用户年龄 */ private int userAge; /** * 手机号 */ private String phone; /** * 创建时间 */ private Long createTime; /** * ipv6 */ private String ipv6; /** * 固定电话 */ private String telephone; //省略get set}下面来新建一个UserController,然后将User作为Controller的请求参数和响应实体测试下smart-doc是如何轻松完成文档生成的。 ...

October 2, 2019 · 1 min · jiezi

持续集成及自动化部署之Jenkins

持续集成及自动化部署工具持续部署[CD]**仅仅单元测试还不够,各个模块必须能够在服务器上运行;**关注点在于项目功能(各个模块)部署至服务器后可以运行,为测试环节或最终用户使用做好准备;持续集成[CI]**经常性、频繁的把所有模块集成在一起进行测试[集成测试],有问题尽早发现;**关注点在于尽早发现项目整体运行问题,尽早解决;持续交付[CD]**用小版本不断进行快速迭代,不断收集用户反馈信息,用最快的速度改进优化;[大版本/release]**关注点在于研发团队的最新代码能够尽快让最终用户体验到;总体目标**好处: ***1.降低风险; ***2.减少重复过程[如编译、测试、打包等固定流程] - 自动化流程; ***3.任何时间、任何地点生成 "可部署的软件"; ***4.增强项目的可见性<1>有效决策;<2>注意到趋势; ***5.建立团队对开发产品的信心;Jenkins<open> | Hudson<Oracle>** 前提知识:Linux基本命令|vim编辑器|Maven项目构建管理|Github|SVN** 可整合Github或Subversion** 人工部署** 自动化部署 *** 搭建持续集成环境:可以把构建、部署自动化,减轻工作量 > deploy web container插件 + > *** dev > git repository > 钩子程序 > jenkins > [GIT插件]> code >打包> war包>部署>Tomcat server > [Maven插件] > + >Jenkins:### Jenkins + SVN: ** 要点: *** 创建虚拟机安装Linux系统:vm1-svn,vm2-jenkins,vm3-application(tomcat); *** 版本控制子系统(SVN): - subversion服务器; - 项目对应版本库; - 版本库中钩子程序; -- linux curl命令:-X:指定请求方式;-v:显示响应结果;-u:携带用户名/密码;-H:携带请求消息头信息; *** 持续集成子系统 - JDK; - Tomcat; - Maven; - Jenkins: -- 主体程序; -- svn插件; -- maven插件; -- Deploy to Web Container插件; ***应用发布子系统 - JDK; - Tomcat;### Jenkins + Github: **要点: *** Jenkins需要部署到外网,因Github无法无法访问内网地址; - 安装Jenkins; *** Jenkins所在主机需要安装GIT,git从GitHub上clone代码; - echo "export PATH=$PATH:/usr/local/git/bin" >> /etc/bashrc # >>追加 - source /etc/bashrc # 使文件生效 *** Jenkins需要指定git程序位置,和指定jdk、maven程序位置类似; - 配置git; *** 在GitHub上使用每个repository的webhook方式远程触发Jenkins构建; - GitHub配置webhook[repository>settings>webhook>add webhook>远程触发的身份验证令牌] *** 在Jenkins内关闭“防止跨站请求伪造”; - 全局安全配置 > CSRF Protection > 取消勾选;

September 11, 2019 · 1 min · jiezi

sonarJenkins-构建代码质量自动化分析平台

1.Sonar 介绍 Sonar 是一个用于管理代码质量的开源工具,可以分析代码中的bug和漏洞以及Code Smells,支持20多种编程语言的检测,如java,c/c++,python,php等语言,当前有超过85000家组织在使用sonar。Sonar可以与DevOps工具链完全整合,可以与大多数构建工具进行内置集成,与Jenkins,TFS / VSTS,TeamCity,Bamboo等持续整合引擎轻松集成,支持众多源代码管理配置工具,如git,svn,cvs等。 官方地址:https://www.sonarqube.org/ 早在2007年,当创建第一行代码时,Sonar的创始人就梦想有一天能够为每个开发人员提供测量其项目代码质量的能力。他的座右铭:“持续检测必须成为持续整合的主流”。 本文的目的就是安装一个sonar,并集成到Jenkins中,实现代码的一个持续质量监测。 2.Sonar 安装 2.1.安装环境介绍 注意:sonar服务器至少需要2G的内存才能有效运行,而操作系统则需要1GB的可用内存。 Centos 7.2安装JDK 1.8安装Jenkins 2.89安装 maven 3.5.2(非必需,用于编译一些插件)mysql 5.6 数据库 (要求版本,不低于5.6)安装完mysql后创建sonar数据库和账号,方式如下: CREATE DATABASE sonar CHARACTER SET utf8 COLLATE utf8_general_ci;GRANT ALL PRIVILEGES ON sonar.* TO 'sonar'@'localhost' IDENTIFIED BY '123456' WITH GRANT OPTION;FLUSH PRIVILEGES;2.2.SonarQube安装 cd /data/package/wget https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-6.6.zipmkdir /data/service/sonar/unzip sonarqube-6.6.zip -d /data/service/sonar/配置启动脚本: [root@c7-node1 ~]# cat /etc/init.d/sonar#!/bin/sh## rc file for SonarQube## chkconfig: 345 96 10# description: SonarQube system (www.sonarsource.org)#### BEGIN INIT INFO# Provides: sonar# Required-Start: $network# Required-Stop: $network# Default-Start: 3 4 5# Default-Stop: 0 1 2 6# Short-Description: SonarQube system (www.sonarsource.org)# Description: SonarQube system (www.sonarsource.org)### END INIT INFO/usr/bin/sonar $*授权启动脚本执行权限,并配置路径 ...

September 9, 2019 · 2 min · jiezi

Maven指南

1 什么是maven Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件。 Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的 可重用性,所以常常用两三行 Maven 构建脚本就可以构建简单的项目。由于 Maven 的面向项目的方法, 许多 Apache Jakarta 项目发文时使用 Maven,而且公司项目采用 Maven 的比例在持续增长。Maven这个 单词来自于意第绪语(犹太语),意为知识的积累,最初在Jakata Turbine项目中用来简化构建过程。当时 有一些项目(有各自Ant build文件),仅有细微的差别,而JAR文件都由CVS来维护。于是希望有一种标准 化的方式构建项目,一个清晰的方式定义项目的组成,一个容易的方式发布项目的信息,以及一种简单的方式 在多个项目中共享JARs。 Maven是一个项目管理工具,它包含了一个项目对象模型 (Project Object Model),一组标准集合,一个 项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),和用来运行 定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑。当你使用Maven的时候,你用一个明确定 义的项目对象模型来描述你的项目,然后Maven可以应用横切的逻辑,这些逻辑来自一组共享的(或者自定义 的)插件。 Maven 有一个生命周期,当你运行 mvn install 的时候被调用。这条命令告诉 Maven 执行一系列的有 序的步骤,直到到达你指定的生命周期。遍历生命周期旅途中的一个影响就是,Maven 运行了许多默认的 插件目标,这些目标完成了像编译和创建一个 JAR 文件这样的工作。此外,Maven能够很方便的帮你管理 项目报告,生成站点,管理JAR文件,等等。1.1 安装 maven官网:https://maven.apache.org/ maven下载地址:https://maven.apache.org/download.cgi如图: 选择其中一个下载下载完成之后解压 可以看到如下目录: bin: 该目录包含maven脚本。包含了mvn运行的脚本,在此目录下输入任意一条命令就是调用这些脚本 boot: 该目录只有一个plexus-classworlds-2.5.2.jar,该jar是maven的类加载框架用来加载自己的类 库,相对于默认的java类加载器,提供了更丰富的语法及配置 config: 该目录包含maven配置文件,可以全局定制maven行为。通常,settings.xml复制到~/.m2/目录下, 在用户范围内定制maven行为。编译工具会优先去~/.m2目录下读取settings.xml文件,如果没有 读取到才会去maven的安装目录下读取settings.xml文件。 lib: 该目录包含了maven运行时需要的java类库。其中注意的一点是:可以在lib包下找到maven内置的超 级POM,一般存放在名叫maven-model-builder的jar包里面如果想在cmd上直接运行,需要设置环境变量中的path。这里就不一一说明了。1.2 本地仓库的安装 修改maven目录下的config的setting.xml把<localRepository>打开,标签里面设置本地仓库的地址, 那么之后所有项目的jar包都装放在这个目录下 如: <localRepository>D:\Inkstone\maven\repository</localRepository> 创建一个maven项目先创建 一个根目录,如果d:\example在d:\example目录下运行mvn archetype:generate然后会在这个目录下生成一个项目的骨架如图: ...

August 18, 2019 · 4 min · jiezi

maven-阿里云镜像-提升依赖下载速度

1. 依赖下载慢我们在下载maven依赖的时候,因为maven仓库默认在国外,所以下载速度很慢,可以在maven的配置文件中加入下列配置,提高maven依赖的下载速度。 2. 解决步骤总共修改两个地方. 一、settings.xml配置文件, 一个 pom.xml 文件.修改maven配置文件settings.xml (当然也可以在用户home目录.m2下面添加一个settings.xml文件,记得备份.) <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror> 二.更改项目的pom.xml配置文件, 重新导入即可 <repositories>        <repository>            <id>nexus-aliyun</id>            <name>Nexus aliyun</name>            <url>http://maven.aliyun.com/nexus...;/url>        </repository></repositories>

August 18, 2019 · 1 min · jiezi

Java秒杀系统实战系列构建SpringBoot多模块项目

摘要:本篇博文是“Java秒杀系统实战系列文章”的第二篇,主要分享介绍如何采用IDEA,基于SpringBoot+SpringMVC+Mybatis+分布式中间件构建一个多模块的项目,即“秒杀系统”!。 内容:传统的基于IDEA构建SpringBoot的项目,是直接借助Spring Initializr插件进行构建,但是这种方式在大部分情况下,只能充当“单模块”的项目,并不能很好的做到“分工明确、职责清晰”的分层原则! 故而为了能更好的管理项目代码以及尽量做到“模块如名”,快速定位给定的类文件或者其他文件的位置,下面我们将基于IDEA、借助Maven构建多模块的项目,其中,其构建的思路如下图所示: ![图片上传中...] 详细的构建过程在本文就不赘述了!文末有提供源码的地址以及构建过程的视频教程!下面重点介绍一下跟“Java秒杀系统”相关的构建步骤。 (1)如下图所示为最终构建成功的项目的整体目录结构: 从该目录结构中可以看出,该项目为一个“聚合型项目”,其中,model模块依赖api模块,server模块依赖model模块,层层依赖!最终在server模块实现“大汇总”,即server模块为整个项目的核心关键所在,像什么“配置文件”、“入口启动类”啥的都在这个模块中! 而且,各个模块的职责是不一样的,分工也很明确,就像model模块,一般人看了就知道这里放的东西应该是跟mybatis或者跟数据库mysql相关的类文件与配置文件等等。 构建好相应的模块之后,就需要往相应的模块添加依赖,即只需要在pom.xml中加入相应的依赖即可,在这里就不贴出来了!(2)在这里主要贴一下server模块入口启动类MainApplication的代码,如下所示: @SpringBootApplication@ImportResource(value = {"classpath:spring/spring-jdbc.xml"})@MapperScan(basePackages = "com.debug.kill.model.mapper")@EnableSchedulingpublic class MainApplication extends SpringBootServletInitializer{ @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(MainApplication.class); } public static void main(String[] args) { SpringApplication.run(MainApplication.class,args); }}其中,该启动类将加载配置文件spring-jdbc.xml(数据库链接信息的配置文件)! 构建完成之后,可以将整个项目采用外置的Tomcat跑起来,运行过程中,观察控制台Console的输出信息,如果没有报错信息,则代表整个项目的搭建是没有问题的!如果出现了问题,建议自己先研究一番并尝试去解决掉!如果仍旧不能解决,可以加文末提供的联系方式进行解决! (4)除此之外,为了让整个项目在前后端分离开发的情况下,前后端的接口交互更加规范(比如响应信息的规范等等),在这里我们采用了通用的一个状态码枚举类StatusCode 跟 一个通用的响应结果类BaseResponse,用于后端在返回响应信息给到前端时进行统一封装。 状态码枚举类StatusCode的源代码如下所示: public enum StatusCode { Success(0,"成功"), Fail(-1,"失败"), InvalidParams(201,"非法的参数!"), UserNotLogin(202,"用户没登录"), ; private Integer code; //状态码code private String msg; //状态码描述信息msg StatusCode(Integer code, String msg) { this.code = code; this.msg = msg; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; }}响应结果类BaseResponse的源代码如下所示: ...

July 16, 2019 · 2 min · jiezi

IDEA中通过maven更新依赖版本手动强制更新依赖

一、前言IntelliJ IDEA自动载入Maven依赖的功能很好用,但有时候会碰到问题,导致pom文件修改却没有触发自动重新载入的动作,此时需要手动强制更新依赖。二、手动更新依赖(idea+maven)(一)方法一右键单击项目;在弹出菜单中选择Maven|Reimport菜单项。(二)方法二点击idea右边的maven,选择项目,并点击左上角那个刷新按钮

July 9, 2019 · 1 min · jiezi

Spring-Boot-打包成的可执行-jar-为什么不能被其他项目依赖

前两天被人问到这样一个问题: “松哥,为什么我的 Spring Boot 项目打包成的 jar ,被其他项目依赖之后,总是报找不到类的错误?” <!--more--> 大伙有这样的疑问,就是因为还没搞清楚可执行 jar 和普通 jar 到底有什么区别?今天松哥就和大家来聊一聊这个问题。 多了一个插件Spring Boot 中默认打包成的 jar 叫做 可执行 jar,这种 jar 不同于普通的 jar,普通的 jar 不可以通过 java -jar xxx.jar 命令执行,普通的 jar 主要是被其他应用依赖,Spring Boot 打成的 jar 可以执行,但是不可以被其他的应用所依赖,即使强制依赖,也无法获取里边的类。但是可执行 jar 并不是 Spring Boot 独有的,Java 工程本身就可以打包成可执行 jar 。 有的小伙伴可能就有疑问了,既然同样是执行 mvn package 命令进行项目打包,为什么 Spring Boot 项目就打成了可执行 jar ,而普通项目则打包成了不可执行 jar 呢? 这我们就不得不提 Spring Boot 项目中一个默认的插件配置 spring-boot-maven-plugin ,这个打包插件存在 5 个方面的功能,从插件命令就可以看出: 五个功能分别是: build-info:生成项目的构建信息文件 build-info.propertiesrepackage:这个是默认 goal,在 mvn package 执行之后,这个命令再次打包生成可执行的 jar,同时将 mvn package 生成的 jar 重命名为 *.originrun:这个可以用来运行 Spring Boot 应用start:这个在 mvn integration-test 阶段,进行 Spring Boot 应用生命周期的管理stop:这个在 mvn integration-test 阶段,进行 Spring Boot 应用生命周期的管理这里功能,默认情况下使用就是 repackage 功能,其他功能要使用,则需要开发者显式配置。 ...

July 9, 2019 · 2 min · jiezi

Docker-Jenkins-Maven代理设置

公司为了省钱,除了一台服务器能够上网之外,其余的都是内网服务器,我把jenkins装在内网服务器下,用Dockder来搭建的,所以就出现题目的问题。怎么设置Docker jenkins容器下的maven http代理,让mvn能下载包。一、进入jenkins容器并查看Maven的安装信息# 进入容器docker exec -it jenkins bash# 查看Maven安装配置cat /var/jenkins_home/hudson.tasks.Maven.xml<?xml version='1.1' encoding='UTF-8'?><hudson.tasks.Maven_-DescriptorImpl> <installations> <hudson.tasks.Maven_-MavenInstallation> <name>maven3.5.2</name> <properties> <hudson.tools.InstallSourceProperty> <installers> <hudson.tasks.Maven_-MavenInstaller> <id>3.5.2</id> </hudson.tasks.Maven_-MavenInstaller> </installers> </hudson.tools.InstallSourceProperty> </properties> </hudson.tasks.Maven_-MavenInstallation> </installations></hudson.tasks.Maven_-DescriptorImpl>可以看到我们这里用的是3.5.2版本那么的Maven所在的目录在 /var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/maven3.5.2二、找到setting.xml并修改# 修改setting文件,如果有挂载,那直接在宿主机上修改即可,免得进来容器里面,还要安装vimvim /var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/maven3.5.2/conf/settings.xml在xml中的settings标签下增加以下内容 <proxies> <proxy> <id>optional</id> <active>true</active> <protocol>http</protocol> <host>代理服务器IP</host> <port>代理服务器端口</port> <!-- <username></username> <password></password> --> </proxy> </proxies>三、重启Jenkins容器docker restart jenkins#重启完,打开jenkins,mvn命令能下载包了

June 25, 2019 · 1 min · jiezi

maven入门

MavenWhat is Maven?构建规范项目的工具项目管理工具,进行打包,测试,部署具有一套规范POMWhat is POMMaven的基本工作单元xml文件存储Maven项目的配置文件(Maven的命令都是先从POM读取命令,然后执行命令)Super POMMaven的默认POM文件,如果POM文件没有指定父POM文件,那么配置都是集成Super POM Minimal POMPOM文件的最低需要的配置元素: projectgroupId:一般是组织名称artifactId:项目的名称version:项目的版本号Maven项目的完全限定名:groupId:artifactId:version packaging元素默认是JAR,还有其他选项是WAR,EAR等等Project Inheritance之前在Super POM一节谈到指定了父POM的继承指定父POM的配置,实现如下: . |--my-app | |-- my-module | | `-- pom.xml `-- pom.xmlmy-app的POM<project> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany.app</groupId> <artifactId>my-app</artifactId> <version>1</version></project>my-module的POM<project> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany.app</groupId> <artifactId>my-module</artifactId> <version>1</version></project>修改my-module的POM,即可实现讲my-app作为一个父POM继承给my-module,实现如下: my-module的POM<project> <parent> <groupId>com.mycompany.app</groupId> <artifactId>my-app</artifactId> <version>1</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany.app</groupId> <artifactId>my-module</artifactId> <version>1</version></project>如果my-app不是作为my-module的父目录,如下: . |-- my-module | `-- pom.xml `-- my-app `-- pom.xml需要配置<relativePath>属性,配置相对my-module的相对路径如下: <project> <parent> <groupId>com.mycompany.app</groupId> <artifactId>my-app</artifactId> <version>1</version> <relativePath>../parent/pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>my-module</artifactId></project>Project Aggregation如果我们想要对一些模块都需要执行相同的命令,但是不想进入每一个模块下进行执行命令,可以使用Aggregation. 目录结构 . |-- my-module | `-- pom.xml `-- pom.xml将my-module模块聚合到my-app,修改my-app的POM文件如下: ...

June 20, 2019 · 1 min · jiezi

动手搭建后端框架Velocity模板引擎的应用

为了提高开发效率,通常会想办法把一些模式固定的重复性的劳动抽取出来,以后再使用的时候,拿来主义就可以了。这样既可以提高开发效率,又降低了出错的风险。 这一思想在我们的日常工作中可以说随处可见,我们完成一项复杂的工程,并不需要面面俱到什么都自己写,我们完全可以利用第三方的jar包让我们达到事半功倍的效果,比如经常使用的apche的commons-lang3包。再比如java中的继承、我们自己封装的工具类等等。 另外一方面,对于源码文件,如果公司有成熟的框架,我们的开发都是遵循着框架制定的约定来进行开发的,我们在创建某一个业务的控制层、业务层、持久层的时候,实际上有相当一部分的工作是重复的。 那么对于源码文件的编写我们能否偷偷懒呢?答案肯定是可以的,我们可以利用模板引擎技术,将不变的部分写在模板文件中,将可变的部分作为变量传递到模板引擎的上下文中,最终生成我们想要的源码文件。 模板引擎的产品有很多,比如前端模板artTemplate、后端模板Velocity、FreeMarker等 本文以Velocity为例,总结一下它在实战中的应用 1.基础知识搭建过程涉及到的基础知识包括:Maven、Velocity、工厂模式、建造者模式、单元测试对于基础不熟悉的同学,建议看一下下面的两篇文章Velocity基础Velocity语法摘要 2.搭建工程2.1模块目录代码生成功能,在我设计的后台框架中,作为一个独立的模块存在,使用Maven构建。builder目录:建造者模式应用。由于代表表结构的Table实体稍显复杂,因此使用了建造者模式构建Table对象。其实不用也可以,因为Table不是很复杂,只是为了复习一下所学过的设计模式知识factory目录:工厂模式应用。在构建源码文件的时候,由于涉及到了Controller、Service、Dao、Domain这几种类型的文件,因此针对不同类型的文件,要使用其对应的处理类,因此使用了工厂模式handler目录:生成源文件的核心代码model目录:在生成domain的时候,由于字段需要从数据库中的表中读取,因此构造了与表对应的实体类方便处理utils目录:工具类Generator.java:程序主文件,调用入口test目录:单元测试 .├── generator.iml├── pom.xml└── src ├── main │   ├── java │   │   └── com │   │   └── wt │   │   └── master │   │   └── generator │   │   ├── Generator.java │   │   ├── builder │   │   │   ├── MySqlTableBuilder.java │   │   │   └── TableBuilder.java │   │   ├── factory │   │   │   └── GeneratorFactory.java │   │   ├── handler │   │   │   ├── BaseGenerator.java │   │   │   ├── ControllerGeneratorHandler.java │   │   │   ├── DomainGeneratorHandler.java │   │   │   ├── MapperGeneratorHandler.java │   │   │   └── ServiceGeneratorHandler.java │   │   ├── model │   │   │   └── Table.java │   │   └── util │   │   ├── JdbcUtils.java │   │   ├── SpringContextUtils.java │   │   ├── TableColumnUtils.java │   │   └── TableInfoUtils.java │   └── resources │   ├── config │   │   ├── applicationContext.xml │   │   └── db.properties │   └── template │   ├── controller.java.vm │   ├── dao.java.vm │   ├── domain.java.vm │   ├── service.java.vm │   └── serviceimpl.java.vm └── test └── com.wt.master.generator └── GeneratorTest.java2.2引入依赖<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>j2ee</artifactId> <groupId>com.wt.master</groupId> <version>1.0-SNAPSHOT</version> <relativePath>../version/</relativePath> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>generator</artifactId> <dependencies> <!-- 模板引擎 --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> </dependency> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>com.wt.master</groupId> <artifactId>core</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.4</version> </dependency> </dependencies></project>3.核心代码3.1模板文件的定义以controller层生成模板为例将不变的部分直接写到.vm文件中将模板文件中,有可能发生变化的部分,抽取为变量,变量的值从VelocityContext中获取在Velocity架构中,有一个上下文的定义,通过上下文,程序将变量放入上下文对象中。而模板从上下文中获取对应变量的值,获取的方式是${变量名},关于Velocity模板文件中的语法,参见上文提到的两篇文章 ...

June 19, 2019 · 5 min · jiezi

基于springsecurityoauth2实现单点登录持续更新

基于spring-security-实现数据库版文章代码地址:链接描述可以下载直接运行,基于springboot2.1.5,springcloud Greenwich版本实现。前面两篇写了认证oauth2通过内存 还有jdbc实现认证中心。接下来我们采用oauth2实现管理系统的单点登录。 说到这里,需要介绍几个注解: @EnableAuthorizationServer 该注解用来开启认证服务,使用该注解表明自己是一个认证服务。 @EnableResourceServer 该注解要用来开启资源保护,表明自己是资源服务器受认证服务保护。 @EnableOAuth2Sso 该注解表示自己是oauth2客户端,也即单点登录客户端 @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true) spring-security默 认禁用注解,使用该注解来判断用户对某个控制层的方法是否具有访问权限 好来,注解介绍完了,闲话少说。我们开始今天的主题“单点登录”。 (1)创建sso-client项目,修改maven依赖: 因为,是web项目需要添加maven依赖。 (2)在启动类加上@EnableOAuth2Sso注解,表明自己是客户端 (3)下面进行最重要的,设置配置文件 因为,前面几个配置在之前章节介绍过,这里只介绍server.servlet.session.cookie.name=OAUTH2SESSION这个配置。 这是个坑,我在没加这个配置之前,授权成功后,还是跳转授权登录页码。认证服务器和浏览器控制台也没有报错信息。只好debug一点点差错。 这里简单介绍下如何查阅源码,首先全局搜索自己的配置 security.oauth2.client.user-authorization-uri=http://localhost:9001/oauth/authorize因为这个地址是认证服务器请求授权的,所以,请求认证的过滤器肯定包含他。搜索的结果如下: 两个结果,一个是我们自己配置的忽略,点开另外一个: ok我们在源码中找到这个类,一直向上找,可以找到OAuth2RestTemplate 同样的,我们可以搜索这个地址,查找在认证服务器中是如何认证的。 跑偏了,还是介绍下这个配置吧,通过这个配置session和认证服务器不一样结局。也可以设置上下文路径 server.servlet.context-path=/sso-client (4)调回来,下来我们创建一个controller文件,用来获取授权用户信息: 在template下创建index.html欢迎页面: (5)启动客户端服务: (6)因为,我们需要请求认证服务器,校验token,因此认证服务器需要开启/oauth/token路径,修改WebSecurityConfig文件添加: (7)启动认证服务,访问客户端首页: http://localhost:9005 如下: 自动跳转到认证服务器登录地址,输入用户名: admin 密码: 123456 登录 你可以把项目修改端口启动试试,登录一个另一个不在需要登录。 未完待续,下一篇介绍资源服务器和认证服务器的集成。 有问题,请留言。

June 2, 2019 · 1 min · jiezi

基于springsecurityoauth2实现oauth2数据库版持续更新

基于spring-security-oauth2实现oauth2数据库版文章代码地址:链接描述可以下载直接运行,基于springboot2.1.5,springcloud Greenwich版本实现 该系列分为两个部分:分为内存实现,数据库实现。其中数据库实现采用RBAC权限角色管理。 上一篇,介绍了oauth2的内存实现,也就是认证服务把客户端和用户信息都存储在内存中,这样不利于拓展,不适合于生产环境。下面,我们开始基于mysql数据库的oauth2实现。 首先,我们创建oauth2数据库,注意编码选择utf-8mb4格式,utf-8是不规范的,mysql也没有进行更改。 好了,现在我们初始化表,sql如下: Drop table if exists oauth_client_details;create table oauth_client_details ( client_id VARCHAR(255) PRIMARY KEY, resource_ids VARCHAR(255), client_secret VARCHAR(255), scope VARCHAR(255), authorized_grant_types VARCHAR(255), web_server_redirect_uri VARCHAR(255), authorities VARCHAR(255), access_token_validity INTEGER, refresh_token_validity INTEGER, additional_information TEXT, autoapprove VARCHAR (255) default 'false') ENGINE=InnoDB DEFAULT CHARSET=utf8; Drop table if exists oauth_access_token;create table oauth_access_token ( token_id VARCHAR(255), token BLOB, authentication_id VARCHAR(255), user_name VARCHAR(255), client_id VARCHAR(255), authentication BLOB, refresh_token VARCHAR(255)) ENGINE=InnoDB DEFAULT CHARSET=utf8; ...

May 31, 2019 · 4 min · jiezi

Spring-Framework系列教程汇总

最近整理出了之前学习Spring Framework系列,记载了一些学习笔记,特地在此罗列出来。大家也可直接关注笔者github(Spring Framework)获取最新资讯。 TutorialSpring-framework-4.x1. Spring Annotation驱动编程2. Java Beans内省机制以及在Spring中的应用3. Java资源管理以及在Spring中的应用4. Spring自定义XML配置扩展Spring-framework-5.x1. 深入Java之国际化2. JSP在Spring中的应用(Annotation版)3. JSP在Spring中的应用(XML版)4. Java Reactive Web设计与实现5. Servlet在Spring中的应用6. Spring5新特性之测试7. Spring5新特性之Web Flux8. Spring Web自动装配(Annotation)Spring-framework-common1. Spring Aware接口应用

May 28, 2019 · 1 min · jiezi

Maven使用技巧

如何查看maven依赖的jar是如何引入的?maven

May 27, 2019 · 1 min · jiezi

Java-Reactive-Web设计与实现

注: 本文是由读者观看小马哥公开课视频过程中的笔记整理而成。更多Spring Framework文章可参看笔者个人github: spring-framework-lesson 。0. 编程模型与并发模型Spring 5实现了一部分Reactive Spring WebFlux: Reactive Web(non-blocking servers in general) Spring Web MVC:传统Servlet Web(servlet applications in general) 0.1 编程模型编程模型:阻塞、非阻塞 NIO:同步+非阻塞,基于事件非阻塞 基本上采用Callback方式当时不阻塞,后续再输出(再回调)0.2 并发模型并发模型: 同步(Sync)异步(Async)0.3 比较同步+非阻塞:线程不会改变,不会切换[线程:main] Observable 添加观察者! [线程:main] 通知所有观察者! [线程:main] 3. 收到数据更新:Hello World [线程:main] 2. 收到数据更新:Hello World [线程:main] 1. 收到数据更新:Hello World 异步+非阻塞:线程会被切换[线程:main] 启动一个JFrame窗口! [线程:AWT-EventQueue-0] 销毁当前窗口! [线程:AWT-EventQueue-0] 窗口被关闭,退出程序!使用Jconsole查看改异步非阻塞程序 等待总数一直在增加,说明异步程序一直在等待。NIO就是无限地在处理,无限地在等待。 1. Reactive概念Reactive Programming:响应式编程,异步非阻塞就是响应式编程(Reactive Programming),与之相对应的是命令式编程。 Reactive并不是一种新的技术,不用Reactive照样可以实现非阻塞(同步、异步均可,推拉模式的结合),比如利用观察者模式实现(比如Java Swing GUI技术)。 Reactive的另外一种实现方式就是消息队列。 1.1 标准概念1.1.1 维基百科讲法https://en.wikipedia.org/wiki... In computing, reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change. With this paradigm it is possible to express static (e.g., arrays) or dynamic (e.g., event emitters) data streams with ease, and also communicate that an inferred dependency within the associated execution model exists, which facilitates the automatic propagation of the changed data flow关键点: ...

May 25, 2019 · 8 min · jiezi

Maven多模块结构下版本管理的正确姿势CI-Friendly-Versions-revision

在使用Maven多模块结构工程时,配置版本是一个比较头疼的事。继承版本,依赖版本,自身版本,都需要单独定义,很是麻烦。但其实Maven已经提供了这种CI版本的管理方式,下面来介绍具体用法。 从Maven 3.5.0-beta-1版本开始,就可以使用${revision}, ${sha1} 和 ${changelist}作为占位符来替换pom文件了。 注意:Idea下使用${revision}定义Parent版本时会提示错误“Reports that usage of properties in modules parent definition is prohibited”,但并不影响使用,只是Idea不支持这种写法而已。 单模块项目<project> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.apache</groupId> <artifactId>apache</artifactId> <version>18</version> </parent> <groupId>org.apache.maven.ci</groupId> <artifactId>ci-parent</artifactId> <name>First CI Friendly</name> <version>${revision}</version> ...</project>这种情况比较简单,只使用了${revision}来替换版本。 还可以用另一种动态添加参数的方式来指定版本 $ mvn -Drevision=1.0.0-SNAPSHOT clean package-D代表设置环境变量 -D,--define <arg> Define a system property或者在(父)项目的properties中定义版本: <project> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.apache</groupId> <artifactId>apache</artifactId> <version>18</version> </parent> <groupId>org.apache.maven.ci</groupId> <artifactId>ci-parent</artifactId> <name>First CI Friendly</name> <version>${revision}</version> ... <properties> <revision>1.0.0-SNAPSHOT</revision> </properties></project>多模块项目现在来看看多模块构建的情况。有一个父项目和一个或多子模块。父pom将如下所示: <project> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.apache</groupId> <artifactId>apache</artifactId> <version>18</version> </parent> <groupId>org.apache.maven.ci</groupId> <artifactId>ci-parent</artifactId> <name>First CI Friendly</name> <version>${revision}</version> ... <properties> <revision>1.0.0-SNAPSHOT</revision> </properties> <modules> <module>child1</module> .. </modules></project>子模块配置: ...

May 24, 2019 · 1 min · jiezi

Maven-中optionaltrueoptional和scopeprovidedscope之间的区别

依赖管理是maven提供的主要功能之一。无论我们需要什么依赖,我们只需将它们添加到POM.xml中。由于maven,所有必要的类和资源都会自动添加到项目的classpath中。 在添加依赖项时,我们可以使用optional标志,或将scope设置为“provided”。在这两种情况下,依赖关系都将在声明它们的模块的classpath中,但是使用将它们定义为依赖关系的模块不会在其他项目中传递它们,即不会形成依赖传递。 从语义来上理解optional可选的,可以理解为此功能/此依赖可选,如果不需要某项功能,可以不引用这个包。 scope provided提供的,可以理解为此包不由我直接提供,需要调用者/容器提供。 举个例子说明二者的使用场景和区别optional现开发了一个类似Hibernate的框架,叫Summer吧,致敬下Spring,提供了多种数据库方言的支持:mysql/oracle/db2/postgresql...每种数据库支持也独立了一个module,Summer的依赖中配置了每种数据库的支持包:summer-mysql-support/summer-oracle-support... 但是实际引用此框架/依赖时,并不需要所有数据库方言的支持。此时可以把数据库的支持包都配置为可选的<optional>true</optional>。引用此框架时,只需按需引入自己需要的方言支持包即可,避免了冗余繁杂的依赖,也降低了jar包冲突的风险。 scope provided现有一普通Web工程,必然会用到servlet-api这个包。但是实际上这个包一定是由容器提供的,因为我们这个web会部署到容器内,容器会提供servlet-api,如果此时项目中再引用的话就会造成重复引用,会有版本不一致的风险。 总结二者从功能来看,都做到了依赖不传递。但在语义上表示不同,使用时按场景选择就好。 参考https://medium.com/@danismaz.furkan/difference-between-optional-true-optional-and-scope-provided-scope-7404ec24fb59https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scopehttps://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html

May 22, 2019 · 1 min · jiezi

Java设计模式综合运用责任链模式进阶

1 责任链模式现存缺点由于责任链大多数都是不纯的情况,本案例中,只要校验失败就直接返回,不继续处理接下去责任链中的其他校验逻辑了,故而出现如果某个部分逻辑是要由多个校验器组成一个整理的校验逻辑的话,则此责任链模式则显现出了它的不足之处了。(责任链模式的具体运用以及原理请参见笔者github wiki 2 责任链模式) 2 改进方式2.1 引入适配器模式关于接口适配器模式原理以及使用场景请参见笔者github wiki 12 适配器模式 。 2.2 引入接口默认方法事例代码请参见工程 design-patterns-business中的 defaultmethod包下的代码。2.2.1 概念java8引入了一个 default medthod 使用 default 关键字Spring 4.2支持加载在默认方法里声明的bean2.2.2 优点用来扩展已有的接口,在对已有接口的使用不产生任何影响的情况下,添加扩展。 比如我们已经投入使用的接口需要拓展一个新的方法,在Java8以前,如果为一个使用的接口增加一个新方法,则我们必须在所有实现类中添加该方法的实现,否则编译会出现异常。如果实现类数量少并且我们有权限修改,可能会工作量相对较少。如果实现类比较多或者我们没有权限修改实现类源代码,这样可能就比较麻烦。而默认方法则解决了这个问题,它提供了一个实现,当没有显示提供其他实现时就采用这个实现,这样新添加的方法将不会破坏现有代码。默认方法的另一个优势是该方法是可选的,子类可以根据不同的需求Override默认实现。 例如,我们定义一个集合接口,其中有增、删、改等操作。如果我们的实现类90%都是以数组保存数据,那么我们可以定义针对这些方法给出默认实现,而对于其他非数组集合或者有其他类似业务,可以选择性复写接口中默认方法。2.2.3 使用原则”类优先” 原则 若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时选择父类中的方法:如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。接口冲突原则 如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突。4.3 项目演示3.1 逻辑梳理由于系统业务需求的变更,目前有两种业务需求, 一种就是按照原来的文件上传需求,上传过程中需要校验操作,只要校验失败了,就直接返回失败信息,整个文件都不需要做处理了。(参见之前的文章 Java设计模式综合运用(门面+模版方法+责任链+策略))另一种就是校验的逻辑都一样,但是如果校验失败的情况,需要继续往下执行,记录一下失败id即可,即需要把失败的记录也保存到数据库中,比如约束字段不符合约束规则的情况,则把此字段置空,然后继续执行其他校验器逻辑即可。(本节需要讨论的问题)3.2 实现方案根据第2节的改进方式可以知道,我们有两种方式改进以上逻辑。 3.2.1 采用适配器模式代码参见2.1版本的,地址为:https://github.com/landy8530/...若采用适配器模式,此处我们会采用接口适配器模式。 接口需要多增加一个不用链式调用的校验方法,定义如下, /** * 业务校验统一接口,增加了接口的默认方法实现,这样可以更加方便且自由选择实现接口的哪些方法。 * @author landyl * @create 10:32 AM 05/09/2018 * @version 2.0 * @since 1.0 */public interface Validator<R extends RequestDetail,F extends RequestFile> { /** * 需要引入责任链的时候,则采用此方法 * @param detail * @param chain * @return * @throws BusinessValidationException */ String doValidate(R detail, F file, ValidatorChain chain) throws BusinessValidationException; /** * 不需要责任链的时候,则可以直接调用此方法的实现即可 * @param detail * @return * @throws BusinessValidationException */ boolean doValidate(R detail, F file) throws BusinessValidationException;}适配器类定义如下抽象类, ...

May 21, 2019 · 2 min · jiezi

Java-设计模式综合运用门面模版方法责任链策略工厂方法

在上一篇文章Java设计模式综合运用(门面+模版方法+责任链+策略)中,笔者写了一篇门面模式、模版方法、责任链跟策略模式的综合运用的事例文章,但是后来笔者发现,在实现策略模式的实现上,发现了一个弊端:那就是如果在后续业务发展中,需要再次增加一个业务策略的时候,则需要再次继承AbstractValidatorHandler类(详情请参见上篇文章),这样就会造成一定的类膨胀。今天我利用注解的方式改造成动态策略模式,这样就只需要关注自己的业务类即可,无需再实现一个类似的Handler类。本文也同步发布至简书,地址:https://www.jianshu.com/p/b86...1. 项目背景1.1 项目简介在公司的一个业务系统中,有这样的一个需求,就是根据不同的业务流程,可以根据不同的组合主键策略进行动态的数据业务查询操作。在本文中,我假设有这样两种业务,客户信息查询和订单信息查询,对应以下枚举类: /** * 业务流程枚举 * @author landyl * @create 11:18 AM 05/07/2018 */public enum WorkflowEnum { ORDER(2), CUSTOMER(3), ; ....}每种业务类型都有自己的组合主键查询规则,并且有自己的查询优先级,比如客户信息查询有以下策略: customerIdrequestIdbirthDate+firstName以上仅是假设性操作,实际业务规则比这复杂的多 1.2 流程梳理主要业务流程,可以参照以下简单的业务流程图。 1.2.1 查询抽象模型 1.2.2 组合主键查询策略 1.2.3 组合主键查询责任链 2. Java注解简介注解的语法比较简单,除了@符号的使用之外,它基本与Java固有语法一致。 2.1 元注解JDK1.5提供了4种标准元注解,专门负责新注解的创建。 注解说明@Target表示该注解可以用于什么地方,可能的ElementType参数有:<br/>CONSTRUCTOR:构造器的声明<br/>FIELD:域声明(包括enum实例)<br/>LOCAL_VARIABLE:局部变量声明<br/>METHOD:方法声明<br/>ACKAGE:包声明<br/>PARAMETER:参数声明<br/>TYPE:类、接口(包括注解类型)或enum声明@Retention表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:<br/>SOURCE:注解将被编译器丢弃<br/>CLASS:注解在class文件中可用,但会被VM丢弃<br/>RUNTIME:JVM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。@Document将注解包含在Javadoc中@Inherited允许子类继承父类中的注解2.2 自定义注解定义一个注解的方式相当简单,如下代码所示: @Target({ElementType.METHOD,ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Inherited@Documented//使用@interface关键字定义注解public @interface Description { /* * 注解方法的定义(其实在注解中也可以看做成员变量)有如下的规定: * 1.不能有参数和抛出异常 * 2.方法返回类型只能为八种基本数据类型和字符串,枚举和注解以及这些类型构成的数组 * 3.可以包含默认值,通过default实现 * 4.如果只有一个方法(成员变量),最好命名为value */ String value(); int count() default 1; //默认值为1}注解的可用的类型包括以下几种:所有基本类型、String、Class、enum、Annotation、以上类型的数组形式。元素不能有不确定的值,即要么有默认值,要么在使用注解的时候提供元素的值。而且元素不能使用null作为默认值。注解在只有一个元素且该元素的名称是value的情况下,在使用注解的时候可以省略“value=”,直接写需要的值即可。 2.3 使用注解如上所示的注解使用如下: /** * @author landyl * @create 2018-01-12:39 PM *///在类上使用定义的Description注解@Description(value="class annotation",count=2)public class Person { private String name; private int age; //在方法上使用定义的Description注解 @Description(value="method annotation",count=3) public String speak() { return "speaking..."; }}使用注解最主要的部分在于对注解的处理,那么就会涉及到注解处理器。从原理上讲,注解处理器就是通过反射机制获取被检查方法上的注解信息,然后根据注解元素的值进行特定的处理。 ...

May 18, 2019 · 2 min · jiezi

Java设计模式综合运用门面模版方法责任链策略

引言:很久没有更新了,主要是工作忙。最近,工作中一个子系统升级,把之前不易扩展的缺点给改进了一下,主要是运用了几个设计模式进行稍微改造了一下。本文也同步发布至简书,地址: https://www.jianshu.com/p/962...1.项目背景在公司的一个实际项目中,需要做一个第三方公司(以下简称GMG)的系统集成工作,把该公司的一些订单数据集成到自己公司平台下,各个订单具有一些共性,但是也有其特有的特征。 经过设计,目前我把订单分为POLICY和BOB类型(暂且这么说吧,反正就是一种订单类型,大家参照着看就OK)。 在订单数据集成到公司平台前,需要对订单数据进行一些必要的业务逻辑校验操作,并且每个订单都有自己的校验逻辑(包含公共的校验逻辑)。 本节介绍的便是整个订单集成系统中的校验逻辑在综合利用设计模式的基础上进行架构设计。 2.校验逻辑本校验逻辑主要分为四个部分: 校验文件名称(RequestValidator.validateFileInfo)校验文件内容中的概要部分(RequestValidator.validateSummary)校验文件内容中的列名称(RequestValidator.validateHeaders)校验文件内容中的明细(RequestValidator.validateDetails)其实上面的RequestValidator的实现逻辑最后都是委托给RequestValidationFacade这个门面类进行相应的校验操作。 3.实现细节3.1 domain介绍主要分为RequestFile和RequestDetail两个domain,RequestFile接收泛型的类型(即RequestFile), 使得其子类能够自动识别相应的RequestDetail的子类。RequestFile为抽象类,定义了以下抽象方法,由子类实现: //由子类实现具体的获取文件明细内容public abstract List<T> getRequestDetails();//由子类实现具体的获取workflow的值public abstract WorkflowEnum getProcessWorkFlow();//由子类实现文件列字段名列表public abstract String[] getDetailHeaders();RequestDetail及其子类就是workflow对应文件的明细内容。 3.2 WorkflowEnum枚举策略本例中如下规定: workflow为WorkflowEnum.POLICY对应文件名为:csync_policy_yyyyMMdd_HHmmss_count.txtworkflow为WorkflowEnum.BOB对应文件名为:csync_bob_integration_yyyyMMdd_HHmmss_count.txt以上校验逻辑在AbstractRequestValidation类相应的子类中实现(validateFileName方法),其实这个枚举贯穿整个校验组件,它就是一个针对每个业务流程定义的一个枚举策略。 3.3 涉及到的设计模式实现思路3.3.1 门面模式在客户端调用程序中,采用门面模式进行统一的入口(门面模式讲究的是脱离具体的业务逻辑代码)。门面模式封装的结果就是避免高层模块深入子系统内部,同时提供系统的高内聚、低耦合的特性。 此案例中,门面类为RequestValidationFacade,然后各个门面方法的参数均为抽象类RequestFile,通过RequestFile->getProcessWorkFlow()决定调用AbstractRequestValidation中的哪个子类。 AbstractRequestValidation类构造方法中定义了如下逻辑: requestValidationHandlerMap.put(this.accessWorkflow(),this.accessBeanName());把子类中Spring自动注入的实体bean缓存到requestValidationHandlerMap中,key即为WorkflowEnum枚举值,value为spring bean name, 然后在门面类中可以通过对应的枚举值取得BeanName,进而得到AbstractRequestValidation相应的子类对象,进行相应的校验操作。 注:这边动态调用到AbstractRequestValidation相应的子类对象,其实也是隐藏着【策略模式】的影子。 类图如下: 3.3.2 模版方法模式在具体的校验逻辑中,用到核心设计模式便是模版方法模式,AbstractRequestValidation抽象类中定义了以下抽象方法: /** * validate the file details * @param errMsg * @param requestFile * @return */ protected abstract StringBuilder validateFileDetails(StringBuilder errMsg,RequestFile requestFile); /** * validate the file name * @param fileName * @return */ protected abstract String validateFileName(String fileName); /** * return the current CSYNC_UPDATE_WORKFLOW.UPDATE_WORKFLOW_ID * @return */ protected abstract WorkflowEnum accessWorkflow(); /** * return the current file name's format ,such as: csync_policy_yyyyMMdd_HHmmss_count.txt * @return */ protected abstract String accessFileNameFormat(); /** * return the subclass's spring bean name * @return */ protected abstract String accessBeanName();以上抽象方法就类似我们常说的钩子函数,由子类实现即可。类图如下图所示: ...

May 18, 2019 · 2 min · jiezi

Java设计模式综合运用动态代理Spring-AOP

本文也同步发布至简书,地址:https://www.jianshu.com/p/f70...AOP设计模式通常运用在日志,校验等业务场景,本文将简单介绍基于Spring的AOP代理模式的运用。 1. 代理模式1.1 概念代理(Proxy)是一种提供了对目标对象另外的访问方式,即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。 1.2 静态代理静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。 1.3 动态代理1.3.1 JDK代理JDK动态代理有以下特点:1.代理对象,不需要实现接口2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)3.动态代理也叫做:JDK代理,接口代理 1.3.2 CGLib代理Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。 JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现。Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)。Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。2. Spring AOP2.1 Spring AOP原理AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理和动态代理,静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。本文以Spring AOP的实现进行分析和介绍。 Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。 Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。 如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。 注意:以上片段引用自文章Spring AOP的实现原理,如有冒犯,请联系笔者删除之,谢谢!Spring AOP判断是JDK代理还是CGLib代理的源码如下(来自org.springframework.aop.framework.DefaultAopProxyFactory): @Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); }}由代码发现,如果配置proxyTargetClass = true了并且目标类非接口的情况,则会使用CGLib代理,否则使用JDK代理。 ...

May 18, 2019 · 3 min · jiezi

关于本体自动构建goldminner的bug心得

一.项目地址https://github.com/dfleischha...该项目的fork量只有2,能不用的尽量别用,太费劲了。二.marven踩坑1.Could not resolve dependencies for project de.uni-mannheim.informatik.dws.goldminer:1.1-Snpshot,failure to find net.sourceforge.owlapi:owlapi:jar:3.2.4 in https://breda.informatik.uni-... was cached in the local repository,resolution will not be reattemped until the update interval of lski has elspsed or updated are forced 解决办法:这个问题在于在pom.xml中给的仓库https://breda.informatik.uni-...,而且3.2.4包根本没有,我这里的解决办法是修改pom.xml文件,将owlapi改为owlapi-api,版本改为3.2.5,具体如下,同时增加一个owlapi-apibinding的depency,否则在后面会报错。<dependency> <groupId>net.sourceforge.owlapi</groupId><artifactId>owlapi-api</artifactId><version>3.2.5-SNAPSHOT</version></dependency> <dependency> <groupId>net.sourceforge.owlapi</groupId> <artifactId>owlapi-apibinding</artifactId> <version>3.2.5-SNAPSHOT</version> </dependency>总结:类似于问题1的解决办法网上会有很多,但基本都是clean、install,实话告诉你,基本没什么用,maven在执行pom时会去仓库down相应的包,如果仓库里都没有,install是完全没用的。 2.unable to find javadoc command该问题解决方式如下: <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <javadocExecutable>C:\Program Files\Java\jdk1.8.0_201\bin\javadoc.exe</javadocExecutable></properties> 3.javadoc 的Failed to execute goal org.apache.maven.plugins,这个解决来自https://blog.csdn.net/m1043/a...,需要注意的是在maven3以上的版本,additionalparam需要替换成additionalJOption。 4.jre与jdk的error:解决办法是在pom里加和setting.xml 里加java变量,这个网上很多,就不赘述。

May 14, 2019 · 1 min · jiezi

5分钟从零构建第一个-Apache-Flink-应用

摘要:在本文中,我们将从零开始,教您如何构建第一个Apache Flink (以下简称Flink)应用程序。开发环境准备Flink 可以运行在 Linux, Max OS X, 或者是 Windows 上。为了开发 Flink 应用程序,在本地机器上需要有 Java 8.x 和 maven 环境。 如果有 Java 8 环境,运行下面的命令会输出如下版本信息: $ java -versionjava version "1.8.0_65"Java(TM) SE Runtime Environment (build 1.8.0_65-b17)Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)如果有 maven 环境,运行下面的命令会输出如下版本信息: $ mvn -versionApache Maven 3.5.4 (1edded0938998edf8bf061f1ceb3cfdeccf443fe; 2018-06-18T02:33:14+08:00)Maven home: /Users/wuchong/dev/mavenJava version: 1.8.0_65, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jreDefault locale: zh_CN, platform encoding: UTF-8OS name: "mac os x", version: "10.13.6", arch: "x86_64", family: "mac"另外我们推荐使用 ItelliJ IDEA (社区免费版已够用)作为 Flink 应用程序的开发 IDE。Eclipse 虽然也可以,但是 Eclipse 在 Scala 和 Java 混合型项目下会有些已知问题,所以不太推荐 Eclipse。下一章节,我们会介绍如何创建一个 Flink 工程并将其导入 ItelliJ IDEA。 ...

May 9, 2019 · 2 min · jiezi

pomxml下的标签的作用

maven中pom标签下的所有标签作用<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.0http://maven.apache.org/maven-v4_0_0.xsd"> <!--父项目的坐标。如果项目中没有规定某个元素的值,那么父项目中的对应值即为项目的默认值。 坐标包括group ID,artifact ID和 version。--> <parent> <!--被继承的父项目的构件标识符--> <artifactId/> <!--被继承的父项目的全球唯一标识符--> <groupId/> <!--被继承的父项目的版本--> <version/> <!-- 父项目的pom.xml文件的相对路径。相对路径允许你选择一个不同的路径。默认值是../pom.xml。Maven首先在构建当前项目的地方寻找父项 目的pom,其次在文件系统的这个位置(relativePath位置),然后在本地仓库,最后在远程仓库寻找父项目的pom。--> <relativePath/> </parent> <!--声明项目描述符遵循哪一个POM模型版本。模型本身的版本很少改变,虽然如此,但它仍然是必不可少的,这是为了当Maven引入了新的特性或者其他模型变更的时候,确保稳定性。--> <modelVersion>4.0.0</modelVersion> <!--项目的全球唯一标识符,通常使用全限定的包名区分该项目和其他项目。并且构建时生成的路径也是由此生成, 如com.mycompany.app生成的相对路径为:/com/mycompany/app--> <groupId>asia.banseon</groupId> <!-- 构件的标识符,它和group ID一起唯一标识一个构件。换句话说,你不能有两个不同的项目拥有同样的artifact ID和groupID;在某个 特定的group ID下,artifact ID也必须是唯一的。构件是项目产生的或使用的一个东西,Maven为项目产生的构件包括:JARs,源 码,二进制发布和WARs等。--> <artifactId>banseon-maven2</artifactId> <!--项目产生的构件类型,例如jar、war、ear、pom。插件可以创建他们自己的构件类型,所以前面列的不是全部构件类型--> <packaging>jar</packaging> <!--项目当前版本,格式为:主版本.次版本.增量版本-限定版本号--> <version>1.0-SNAPSHOT</version> <!--项目的名称, Maven产生的文档用--> <name>banseon-maven</name> <!--项目主页的URL, Maven产生的文档用--> <url>http://www.baidu.com/banseon</url> <!-- 项目的详细描述, Maven 产生的文档用。 当这个元素能够用HTML格式描述时(例如,CDATA中的文本会被解析器忽略,就可以包含HTML标 签), 不鼓励使用纯文本描述。如果你需要修改产生的web站点的索引页面,你应该修改你自己的索引页文件,而不是调整这里的文档。--> <description>A maven project to study maven.</description> <!--描述了这个项目构建环境中的前提条件。--> <prerequisites> <!--构建该项目或使用该插件所需要的Maven的最低版本--> <maven/> </prerequisites> <!--项目的问题管理系统(Bugzilla, Jira, Scarab,或任何你喜欢的问题管理系统)的名称和URL,本例为 jira--> <issueManagement> <!--问题管理系统(例如jira)的名字,--> <system>jira</system> <!--该项目使用的问题管理系统的URL--> <url>http://jira.baidu.com/banseon</url> </issueManagement> <!--项目持续集成信息--> <ciManagement> <!--持续集成系统的名字,例如continuum--> <system/> <!--该项目使用的持续集成系统的URL(如果持续集成系统有web接口的话)。--> <url/> <!--构建完成时,需要通知的开发者/用户的配置项。包括被通知者信息和通知条件(错误,失败,成功,警告)--> <notifiers> <!--配置一种方式,当构建中断时,以该方式通知用户/开发者--> <notifier> <!--传送通知的途径--> <type/> <!--发生错误时是否通知--> <sendOnError/> <!--构建失败时是否通知--> <sendOnFailure/> <!--构建成功时是否通知--> <sendOnSuccess/> <!--发生警告时是否通知--> <sendOnWarning/> <!--不赞成使用。通知发送到哪里--> <address/> <!--扩展配置项--> <configuration/> </notifier> </notifiers> </ciManagement> <!--项目创建年份,4位数字。当产生版权信息时需要使用这个值。--> <inceptionYear/> <!--项目相关邮件列表信息--> <mailingLists> <!--该元素描述了项目相关的所有邮件列表。自动产生的网站引用这些信息。--> <mailingList> <!--邮件的名称--> <name>Demo</name> <!--发送邮件的地址或链接,如果是邮件地址,创建文档时,mailto: 链接会被自动创建--> <post>banseon@126.com</post> <!--订阅邮件的地址或链接,如果是邮件地址,创建文档时,mailto: 链接会被自动创建--> <subscribe>banseon@126.com</subscribe> <!--取消订阅邮件的地址或链接,如果是邮件地址,创建文档时,mailto: 链接会被自动创建--> <unsubscribe>banseon@126.com</unsubscribe> <!--你可以浏览邮件信息的URL--> <archive>http:/hi.baidu.com/banseon/demo/dev/</archive> </mailingList> </mailingLists> <!--项目开发者列表--> <developers> <!--某个项目开发者的信息--> <developer> <!--SCM里项目开发者的唯一标识符--> <id>HELLO WORLD</id> <!--项目开发者的全名--> <name>banseon</name> <!--项目开发者的email--> <email>banseon@126.com</email> <!--项目开发者的主页的URL--> <url/> <!--项目开发者在项目中扮演的角色,角色元素描述了各种角色--> <roles> <role>Project Manager</role> <role>Architect</role> </roles> <!--项目开发者所属组织--> <organization>demo</organization> <!--项目开发者所属组织的URL--> <organizationUrl>http://hi.baidu.com/banseon</organizationUrl> <!--项目开发者属性,如即时消息如何处理等--> <properties> <dept>No</dept> </properties> <!--项目开发者所在时区, -11到12范围内的整数。--> <timezone>-5</timezone> </developer> </developers> <!--项目的其他贡献者列表--> <contributors> <!--项目的其他贡献者。参见developers/developer元素--> <contributor> <name/><email/><url/><organization/><organizationUrl/><roles/><timezone/><properties/> </contributor> </contributors> <!--该元素描述了项目所有License列表。 应该只列出该项目的license列表,不要列出依赖项目的 license列表。如果列出多个license,用户可以选择它们中的一个而不是接受所有license。--> <licenses> <!--描述了项目的license,用于生成项目的web站点的license页面,其他一些报表和validation也会用到该元素。--> <license> <!--license用于法律上的名称--> <name>Apache 2</name> <!--官方的license正文页面的URL--> <url>http://www.baidu.com/banseon/LICENSE-2.0.txt</url> <!--项目分发的主要方式: repo,可以从Maven库下载 manual, 用户必须手动下载和安装依赖--> <distribution>repo</distribution> <!--关于license的补充信息--> <comments>A business-friendly OSS license</comments> </license> </licenses> <!--SCM(Source Control Management)标签允许你配置你的代码库,供Maven web站点和其它插件使用。--> <scm> <!--SCM的URL,该URL描述了版本库和如何连接到版本库。欲知详情,请看SCMs提供的URL格式和列表。该连接只读。--> <connection> scm:svn:http://svn.baidu.com/banseon/maven/banseon/banseon-maven2-trunk(dao-trunk) </connection> <!--给开发者使用的,类似connection元素。即该连接不仅仅只读--> <developerConnection> scm:svn:http://svn.baidu.com/banseon/maven/banseon/dao-trunk </developerConnection> <!--当前代码的标签,在开发阶段默认为HEAD--> <tag/> <!--指向项目的可浏览SCM库(例如ViewVC或者Fisheye)的URL。--> <url>http://svn.baidu.com/banseon</url> </scm> <!--描述项目所属组织的各种属性。Maven产生的文档用--> <organization> <!--组织的全名--> <name>demo</name> <!--组织主页的URL--> <url>http://www.baidu.com/banseon</url> </organization> <!--构建项目需要的信息--> <build> <!--该元素设置了项目源码目录,当构建项目的时候,构建系统会编译目录里的源码。该路径是相对于pom.xml的相对路径。--> <sourceDirectory/> <!--该元素设置了项目脚本源码目录,该目录和源码目录不同:绝大多数情况下,该目录下的内容 会被拷贝到输出目录(因为脚本是被解释的,而不是被编译的)。--> <scriptSourceDirectory/> <!--该元素设置了项目单元测试使用的源码目录,当测试项目的时候,构建系统会编译目录里的源码。该路径是相对于pom.xml的相对路径。--> <testSourceDirectory/> <!--被编译过的应用程序class文件存放的目录。--> <outputDirectory/> <!--被编译过的测试class文件存放的目录。--> <testOutputDirectory/> <!--使用来自该项目的一系列构建扩展--> <extensions> <!--描述使用到的构建扩展。--> <extension> <!--构建扩展的groupId--> <groupId/> <!--构建扩展的artifactId--> <artifactId/> <!--构建扩展的版本--> <version/> </extension> </extensions> <!--当项目没有规定目标(Maven2 叫做阶段)时的默认值--> <defaultGoal/> <!--这个元素描述了项目相关的所有资源路径列表,例如和项目相关的属性文件,这些资源被包含在最终的打包文件里。--> <resources> <!--这个元素描述了项目相关或测试相关的所有资源路径--> <resource> <!-- 描述了资源的目标路径。该路径相对target/classes目录(例如${project.build.outputDirectory})。举个例 子,如果你想资源在特定的包里(org.apache.maven.messages),你就必须该元素设置为org/apache/maven /messages。然而,如果你只是想把资源放到源码目录结构里,就不需要该配置。--> <targetPath/> <!--是否使用参数值代替参数名。参数值取自properties元素或者文件里配置的属性,文件在filters元素里列出。--> <filtering/> <!--描述存放资源的目录,该路径相对POM路径--> <directory/> <!--包含的模式列表,例如**/*.xml.--> <includes/> <!--排除的模式列表,例如**/*.xml--> <excludes/> </resource> </resources> <!--这个元素描述了单元测试相关的所有资源路径,例如和单元测试相关的属性文件。--> <testResources> <!--这个元素描述了测试相关的所有资源路径,参见build/resources/resource元素的说明--> <testResource> <targetPath/><filtering/><directory/><includes/><excludes/> </testResource> </testResources> <!--构建产生的所有文件存放的目录--> <directory/> <!--产生的构件的文件名,默认值是${artifactId}-${version}。--> <finalName/> <!--当filtering开关打开时,使用到的过滤器属性文件列表--> <filters/> <!--子项目可以引用的默认插件信息。该插件配置项直到被引用时才会被解析或绑定到生命周期。给定插件的任何本地配置都会覆盖这里的配置--> <pluginManagement> <!--使用的插件列表 。--> <plugins> <!--plugin元素包含描述插件所需要的信息。--> <plugin> <!--插件在仓库里的group ID--> <groupId/> <!--插件在仓库里的artifact ID--> <artifactId/> <!--被使用的插件的版本(或版本范围)--> <version/> <!--是否从该插件下载Maven扩展(例如打包和类型处理器),由于性能原因,只有在真需要下载时,该元素才被设置成enabled。--> <extensions/> <!--在构建生命周期中执行一组目标的配置。每个目标可能有不同的配置。--> <executions> <!--execution元素包含了插件执行需要的信息--> <execution> <!--执行目标的标识符,用于标识构建过程中的目标,或者匹配继承过程中需要合并的执行目标--> <id/> <!--绑定了目标的构建生命周期阶段,如果省略,目标会被绑定到源数据里配置的默认阶段--> <phase/> <!--配置的执行目标--> <goals/> <!--配置是否被传播到子POM--> <inherited/> <!--作为DOM对象的配置--> <configuration/> </execution> </executions> <!--项目引入插件所需要的额外依赖--> <dependencies> <!--参见dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> <!--任何配置是否被传播到子项目--> <inherited/> <!--作为DOM对象的配置--> <configuration/> </plugin> </plugins> </pluginManagement> <!--使用的插件列表--> <plugins> <!--参见build/pluginManagement/plugins/plugin元素--> <plugin> <groupId/><artifactId/><version/><extensions/> <executions> <execution> <id/><phase/><goals/><inherited/><configuration/> </execution> </executions> <dependencies> <!--参见dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> <goals/><inherited/><configuration/> </plugin> </plugins> </build> <!--在列的项目构建profile,如果被激活,会修改构建处理--> <profiles> <!--根据环境参数或命令行参数激活某个构建处理--> <profile> <!--构建配置的唯一标识符。即用于命令行激活,也用于在继承时合并具有相同标识符的profile。--> <id/> <!--自动触发profile的条件逻辑。Activation是profile的开启钥匙。profile的力量来自于它 能够在某些特定的环境中自动使用某些特定的值;这些环境通过activation元素指定。activation元素并不是激活profile的唯一方式。--> <activation> <!--profile默认是否激活的标志--> <activeByDefault/> <!--当匹配的jdk被检测到,profile被激活。例如,1.4激活JDK1.4,1.4.0_2,而!1.4激活所有版本不是以1.4开头的JDK。--> <jdk/> <!--当匹配的操作系统属性被检测到,profile被激活。os元素可以定义一些操作系统相关的属性。--> <os> <!--激活profile的操作系统的名字--> <name>Windows XP</name> <!--激活profile的操作系统所属家族(如 'windows')--> <family>Windows</family> <!--激活profile的操作系统体系结构 --> <arch>x86</arch> <!--激活profile的操作系统版本--> <version>5.1.2600</version> </os> <!--如果Maven检测到某一个属性(其值可以在POM中通过${名称}引用),其拥有对应的名称和值,Profile就会被激活。如果值 字段是空的,那么存在属性名称字段就会激活profile,否则按区分大小写方式匹配属性值字段--> <property> <!--激活profile的属性的名称--> <name>mavenVersion</name> <!--激活profile的属性的值--> <value>2.0.3</value> </property> <!--提供一个文件名,通过检测该文件的存在或不存在来激活profile。missing检查文件是否存在,如果不存在则激活 profile。另一方面,exists则会检查文件是否存在,如果存在则激活profile。--> <file> <!--如果指定的文件存在,则激活profile。--> <exists>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/</exists> <!--如果指定的文件不存在,则激活profile。--> <missing>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/</missing> </file> </activation> <!--构建项目所需要的信息。参见build元素--> <build> <defaultGoal/> <resources> <resource> <targetPath/><filtering/><directory/><includes/><excludes/> </resource> </resources> <testResources> <testResource> <targetPath/><filtering/><directory/><includes/><excludes/> </testResource> </testResources> <directory/><finalName/><filters/> <pluginManagement> <plugins> <!--参见build/pluginManagement/plugins/plugin元素--> <plugin> <groupId/><artifactId/><version/><extensions/> <executions> <execution> <id/><phase/><goals/><inherited/><configuration/> </execution> </executions> <dependencies> <!--参见dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> <goals/><inherited/><configuration/> </plugin> </plugins> </pluginManagement> <plugins> <!--参见build/pluginManagement/plugins/plugin元素--> <plugin> <groupId/><artifactId/><version/><extensions/> <executions> <execution> <id/><phase/><goals/><inherited/><configuration/> </execution> </executions> <dependencies> <!--参见dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> <goals/><inherited/><configuration/> </plugin> </plugins> </build> <!--模块(有时称作子项目) 被构建成项目的一部分。列出的每个模块元素是指向该模块的目录的相对路径--> <modules/> <!--发现依赖和扩展的远程仓库列表。--> <repositories> <!--参见repositories/repository元素--> <repository> <releases> <enabled/><updatePolicy/><checksumPolicy/> </releases> <snapshots> <enabled/><updatePolicy/><checksumPolicy/> </snapshots> <id/><name/><url/><layout/> </repository> </repositories> <!--发现插件的远程仓库列表,这些插件用于构建和报表--> <pluginRepositories> <!--包含需要连接到远程插件仓库的信息.参见repositories/repository元素--> <pluginRepository> <releases> <enabled/><updatePolicy/><checksumPolicy/> </releases> <snapshots> <enabled/><updatePolicy/><checksumPolicy/> </snapshots> <id/><name/><url/><layout/> </pluginRepository> </pluginRepositories> <!--该元素描述了项目相关的所有依赖。 这些依赖组成了项目构建过程中的一个个环节。它们自动从项目定义的仓库中下载。要获取更多信息,请看项目依赖机制。--> <dependencies> <!--参见dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> <!--不赞成使用. 现在Maven忽略该元素.--> <reports/> <!--该元素包括使用报表插件产生报表的规范。当用户执行“mvn site”,这些报表就会运行。 在页面导航栏能看到所有报表的链接。参见reporting元素--> <reporting> ...... </reporting> <!--参见dependencyManagement元素--> <dependencyManagement> <dependencies> <!--参见dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> </dependencyManagement> <!--参见distributionManagement元素--> <distributionManagement> ...... </distributionManagement> <!--参见properties元素--> <properties/> </profile> </profiles> <!--模块(有时称作子项目) 被构建成项目的一部分。列出的每个模块元素是指向该模块的目录的相对路径--> <modules/> <!--发现依赖和扩展的远程仓库列表。--> <repositories> <!--包含需要连接到远程仓库的信息--> <repository> <!--如何处理远程仓库里发布版本的下载--> <releases> <!--true或者false表示该仓库是否为下载某种类型构件(发布版,快照版)开启。 --> <enabled/> <!--该元素指定更新发生的频率。Maven会比较本地POM和远程POM的时间戳。这里的选项是:always(一直),daily(默认,每日),interval:X(这里X是以分钟为单位的时间间隔),或者never(从不)。--> <updatePolicy/> <!--当Maven验证构件校验文件失败时该怎么做:ignore(忽略),fail(失败),或者warn(警告)。--> <checksumPolicy/> </releases> <!-- 如何处理远程仓库里快照版本的下载。有了releases和snapshots这两组配置,POM就可以在每个单独的仓库中,为每种类型的构件采取不同的 策略。例如,可能有人会决定只为开发目的开启对快照版本下载的支持。参见repositories/repository/releases元素 --> <snapshots> <enabled/><updatePolicy/><checksumPolicy/> </snapshots> <!--远程仓库唯一标识符。可以用来匹配在settings.xml文件里配置的远程仓库--> <id>banseon-repository-proxy</id> <!--远程仓库名称--> <name>banseon-repository-proxy</name> <!--远程仓库URL,按protocol://hostname/path形式--> <url>http://192.168.1.169:9999/repository/</url> <!-- 用于定位和排序构件的仓库布局类型-可以是default(默认)或者legacy(遗留)。Maven 2为其仓库提供了一个默认的布局;然 而,Maven 1.x有一种不同的布局。我们可以使用该元素指定布局是default(默认)还是legacy(遗留)。--> <layout>default</layout> </repository> </repositories> <!--发现插件的远程仓库列表,这些插件用于构建和报表--> <pluginRepositories> <!--包含需要连接到远程插件仓库的信息.参见repositories/repository元素--> <pluginRepository> ...... </pluginRepository> </pluginRepositories> <!--该元素描述了项目相关的所有依赖。 这些依赖组成了项目构建过程中的一个个环节。它们自动从项目定义的仓库中下载。要获取更多信息,请看项目依赖机制。--> <dependencies> <dependency> <!--依赖的group ID--> <groupId>org.apache.maven</groupId> <!--依赖的artifact ID--> <artifactId>maven-artifact</artifactId> <!--依赖的版本号。 在Maven 2里, 也可以配置成版本号的范围。--> <version>3.8.1</version> <!-- 依赖类型,默认类型是jar。它通常表示依赖的文件的扩展名,但也有例外。一个类型可以被映射成另外一个扩展名或分类器。类型经常和使用的打包方式对应, 尽管这也有例外。一些类型的例子:jar,war,ejb-client和test-jar。如果设置extensions为 true,就可以在 plugin里定义新的类型。所以前面的类型的例子不完整。--> <type>jar</type> <!-- 依赖的分类器。分类器可以区分属于同一个POM,但不同构建方式的构件。分类器名被附加到文件名的版本号后面。例如,如果你想要构建两个单独的构件成 JAR,一个使用Java 1.4编译器,另一个使用Java 6编译器,你就可以使用分类器来生成两个单独的JAR构件。--> <classifier></classifier> <!--依赖范围。在项目发布过程中,帮助决定哪些构件被包括进来。欲知详情请参考依赖机制。 - compile :默认范围,用于编译 - provided:类似于编译,但支持你期待jdk或者容器提供,类似于classpath - runtime: 在执行时需要使用 - test: 用于test任务时使用 - system: 需要外在提供相应的元素。通过systemPath来取得 - systemPath: 仅用于范围为system。提供相应的路径 - optional: 当项目自身被依赖时,标注依赖是否传递。用于连续依赖时使用--> <scope>test</scope> <!--仅供system范围使用。注意,不鼓励使用这个元素,并且在新的版本中该元素可能被覆盖掉。该元素为依赖规定了文件系统上的路径。需要绝对路径而不是相对路径。推荐使用属性匹配绝对路径,例如${java.home}。--> <systemPath></systemPath> <!--当计算传递依赖时, 从依赖构件列表里,列出被排除的依赖构件集。即告诉maven你只依赖指定的项目,不依赖项目的依赖。此元素主要用于解决版本冲突问题--> <exclusions> <exclusion> <artifactId>spring-core</artifactId> <groupId>org.springframework</groupId> </exclusion> </exclusions> <!--可选依赖,如果你在项目B中把C依赖声明为可选,你就需要在依赖于B的项目(例如项目A)中显式的引用对C的依赖。可选依赖阻断依赖的传递性。--> <optional>true</optional> </dependency> </dependencies> <!--不赞成使用. 现在Maven忽略该元素.--> <reports></reports> <!--该元素描述使用报表插件产生报表的规范。当用户执行“mvn site”,这些报表就会运行。 在页面导航栏能看到所有报表的链接。--> <reporting> <!--true,则,网站不包括默认的报表。这包括“项目信息”菜单中的报表。--> <excludeDefaults/> <!--所有产生的报表存放到哪里。默认值是${project.build.directory}/site。--> <outputDirectory/> <!--使用的报表插件和他们的配置。--> <plugins> <!--plugin元素包含描述报表插件需要的信息--> <plugin> <!--报表插件在仓库里的group ID--> <groupId/> <!--报表插件在仓库里的artifact ID--> <artifactId/> <!--被使用的报表插件的版本(或版本范围)--> <version/> <!--任何配置是否被传播到子项目--> <inherited/> <!--报表插件的配置--> <configuration/> <!--一组报表的多重规范,每个规范可能有不同的配置。一个规范(报表集)对应一个执行目标 。例如,有1,2,3,4,5,6,7,8,9个报表。1,2,5构成A报表集,对应一个执行目标。2,5,8构成B报表集,对应另一个执行目标--> <reportSets> <!--表示报表的一个集合,以及产生该集合的配置--> <reportSet> <!--报表集合的唯一标识符,POM继承时用到--> <id/> <!--产生报表集合时,被使用的报表的配置--> <configuration/> <!--配置是否被继承到子POMs--> <inherited/> <!--这个集合里使用到哪些报表--> <reports/> </reportSet> </reportSets> </plugin> </plugins> </reporting> <!-- 继承自该项目的所有子项目的默认依赖信息。这部分的依赖信息不会被立即解析,而是当子项目声明一个依赖(必须描述group ID和 artifact ID信息),如果group ID和artifact ID以外的一些信息没有描述,则通过group ID和artifact ID 匹配到这里的依赖,并使用这里的依赖信息。--> <dependencyManagement> <dependencies> <!--参见dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> </dependencyManagement> <!--项目分发信息,在执行mvn deploy后表示要发布的位置。有了这些信息就可以把网站部署到远程服务器或者把构件部署到远程仓库。--> <distributionManagement> <!--部署项目产生的构件到远程仓库需要的信息--> <repository> <!--是分配给快照一个唯一的版本号(由时间戳和构建流水号)?还是每次都使用相同的版本号?参见repositories/repository元素--> <uniqueVersion/> <id>banseon-maven2</id> <name>banseon maven2</name> <url>file://${basedir}/target/deploy</url> <layout/> </repository> <!--构件的快照部署到哪里?如果没有配置该元素,默认部署到repository元素配置的仓库,参见distributionManagement/repository元素--> <snapshotRepository> <uniqueVersion/> <id>banseon-maven2</id> <name>Banseon-maven2 Snapshot Repository</name> <url>scp://svn.baidu.com/banseon:/usr/local/maven-snapshot</url> <layout/> </snapshotRepository> <!--部署项目的网站需要的信息--> <site> <!--部署位置的唯一标识符,用来匹配站点和settings.xml文件里的配置--> <id>banseon-site</id> <!--部署位置的名称--> <name>business api website</name> <!--部署位置的URL,按protocol://hostname/path形式--> <url> scp://svn.baidu.com/banseon:/var/www/localhost/banseon-web </url> </site> <!--项目下载页面的URL。如果没有该元素,用户应该参考主页。使用该元素的原因是:帮助定位那些不在仓库里的构件(由于license限制)。--> <downloadUrl/> <!--如果构件有了新的group ID和artifact ID(构件移到了新的位置),这里列出构件的重定位信息。--> <relocation> <!--构件新的group ID--> <groupId/> <!--构件新的artifact ID--> <artifactId/> <!--构件新的版本号--> <version/> <!--显示给用户的,关于移动的额外信息,例如原因。--> <message/> </relocation> <!-- 给出该构件在远程仓库的状态。不得在本地项目中设置该元素,因为这是工具自动更新的。有效的值有:none(默认),converted(仓库管理员从 Maven 1 POM转换过来),partner(直接从伙伴Maven 2仓库同步过来),deployed(从Maven 2实例部 署),verified(被核实时正确的和最终的)。--> <status/> </distributionManagement> <!--以值替代名称,Properties可以在整个POM中使用,也可以作为触发条件(见settings.xml配置文件里activation元素的说明)。格式是<name>value</name>。--> <properties/></project>

May 9, 2019 · 4 min · jiezi

maven梳理

常用命令mvn -v 或者 mvn -version 验证环境变量。mvn help:system 打印出所有的系统属性和环境变量。mvn compile编译项目源代码(不会编译test 目录的元代)(会产生target 文件)会去中央仓库下载项目所依赖的jar包,最后将jar 包的依赖添加classpath 路径中。mvn test运行应用程序中的单元测试。mvn test-compile 编译测试代码,compile 之后生成的targer 文件夹 主程序编译在classes 文件夹下面,测试程序代码放在test-classes 文件夹下。mvn clean删除target 文件夹。mvn install 安装项目依赖的jar 到本地仓库中。mvn clean compile test组合使用mvn clean install 本地仓库路径配置 conf/settings.xml修改: <!-- localRepository | The path to the local repository maven will use to store artifacts. | | Default: ${user.home}/.m2/repository <localRepository>/path/to/local/repo</localRepository> -->推荐不要去修改maven 安装目录下的conf/settings.xml (全局),建议拷贝settings.xml 到对应的本地仓库目录下面(默认:%USERPROFILE%\.m2/settings.xml),存放路径: groupId+artifactId(com.cashew.maven+maven-demo1) 即comcashewmavenmaven-demo1。 settings.xml详解 远程镜像仓库配置我们mvn compile的时候maven会去本地仓库查找是否有对应的jar(依赖),如果没有默认会去maven 中央仓库进行下载,Downloading:https://repo.maven.apache.org/maven2/junit/junit/xxx maven 的中央远程仓库地址是 lib/maven-model-builder-3.3.9.jar中pom-4.0.0.xml文件: ...

May 9, 2019 · 2 min · jiezi

阿里云Kubernetes服务上使用Tekton完成应用发布初体验

Tekton 是一个功能强大且灵活的 Kubernetes 原生开源框架,用于创建持续集成和交付(CI/CD)系统。通过抽象底层实现细节,用户可以跨多云平台和本地系统进行构建、测试和部署。 本文是基于阿里云Kubernetes服务部署Tekton Pipeline,并使用它完成源码拉取、应用打包、镜像推送和应用部署的实践过程。 Tekton Pipeline中有5类对象,核心理念是通过定义yaml定义构建过程.构建任务的状态存放在status字段中。 其中5类对象分别是:PipelineResouce、Task、TaskRun、Pipeline、PipelineRun。 Task是单个任务的构建过程,需要通过定义TaskRun任务去运行Task。 Pipeline包含多个Task,并在此基础上定义input和output,input和output以PipelineResource作为交付。 PipelineResource是可用于input和output的对象集合。 同样地,需要定义PipelineRun才会运行Pipeline。 1. 在阿里云Kubernetes集群中部署Tekton Pipelinekubectl apply --filename https://storage.googleapis.com/tekton-releases/latest/release.yaml查看Tekton Pipelines组件是否运行正常: $ kubectl -n tekton-pipelines get poNAME READY STATUS RESTARTS AGEtekton-pipelines-controller-6bcd7ff5d6-vzmrh 1/1 Running 0 25htekton-pipelines-webhook-6856cf9c47-l6nj6 1/1 Running 0 25h2. 创建Git Resource, Registry Resource编辑 git-pipeline-resource.yaml : apiVersion: tekton.dev/v1alpha1kind: PipelineResourcemetadata: name: git-pipeline-resourcespec: type: git params: - name: revision value: tekton - name: url value: https://code.aliyun.com/haoshuwei/jenkins-demo.gitgit repo的分支名称为 tekton 。 编辑 registry-pipeline-resource.yaml : apiVersion: tekton.dev/v1alpha1kind: PipelineResourcemetadata: name: registry-pipeline-resourcespec: type: image params: - name: url value: registry.cn-hangzhou.aliyuncs.com/haoshuwei/tekton-demo容器镜像仓库地址为 registry.cn-hangzhou.aliyuncs.com/haoshuwei/tekton-demo, 标签为 latest ...

May 7, 2019 · 4 min · jiezi

用maven将dubbo工程打成jar包运行

maven打包方式使用maven打包插件maven-jar-plugin在pom.xml文件最后新增以下代码。maven-dependency-plugin是指将依赖的jar包复制到指定目录maven-resources-plugin将依赖的resources复制到指定目录 <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.6</version> <configuration> <archive> <manifest> <!-- 是否依赖外部jar包 --> <addClasspath>true</addClasspath> <!-- 依赖外部jar包路径 --> <classpathPrefix>lib/</classpathPrefix> <!-- 启动函数 --> <mainClass>com.alibaba.dubbo.container.Main</mainClass> </manifest> </archive> <!-- 打包之后输出目录 --> <outputDirectory>${project.build.directory}/maven-archiver</outputDirectory><!-- 剔除已打包的配置文件 --> <excludes> <exclude>*.*</exclude> <exclude>config/*</exclude> <exclude>config/tencent/*</exclude> <exclude>META-INF/spring/*</exclude> </excludes> </configuration> </plugin> <!-- 拷贝依赖的jar包到lib目录 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.8</version> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory> ${project.build.directory}/maven-archiver/lib </outputDirectory> </configuration> </execution> </executions> </plugin><!-- 拷贝依赖的资源文件包到resources目录 --> <plugin> <artifactId>maven-resources-plugin</artifactId> <executions> <execution> <id>copy-resources</id> <phase>package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/maven-archiver/resources</outputDirectory> <resources> <resource> <directory>${basedir}/src/main/resources</directory> <filtering>true</filtering> </resource> </resources> </configuration> </execution> </executions> </plugin> </plugins> </build>运行jar包方式打包之后的目录结构包含了class文件,以及需要的配置文件信息(不包含excludes的配置文件)在MANIFEST.MF中包含了运行需要的信息 ...

April 29, 2019 · 1 min · jiezi

1Maven-环境搭建

注意事项先装好jdkMac OS$ tar -zxvf ~/dev/doc/apache-maven-3.5.4-bin.tar.gz -C ~/dev/tools/$ mv ~/dev/tools/apache-maven-3.5.4/ ~/dev/tools/maven-3.5.4$ ln -s ~/dev/tools/maven-3.5.4/ ~/dev/tools/maven$ vim ~/.bash_profile export M2_HOME=/home/user000/tools/maven export PATH=$PATH:$M2_HOME/bin$ source ~/.bash_profile$ mvn -v$ vim ~/dev/tools/maven/conf/settings.xml配置默认JDK版本 <profile> <id>jdk-1.8</id> <activation> <activeByDefault>true</activeByDefault> <jdk>1.8</jdk> </activation> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> </properties> </profile>阿里云镜像 <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror>

April 27, 2019 · 1 min · jiezi

Hive将UDF编译到源码中idea

有时候需要改写源码,比如将常用的某个UDF放在源码中,启动即可使用。在Linux上直接改写源码是很容易出错的,因为vim没有检测提示,直到打包时过了很久才报错,并找到日志才发现是哪里写错了,而且提示的也不清楚。所以推荐使用idea来完成改源码的操作,好处不言而喻。 1.下载解压hive源码,用idea打开为Maven项目(jdk1.8),这时所有的依赖就会自动下载 2.将写好的UDF的java代码放在org.apache.hadoop.hive.ql.udf包下 3.在org.apache.hadoop.hive.ql.exec.FunctionRegistry类中静态代码块添加注册 4.Maven打包 1)点掉tests,相当于-DskipTests=true2)命令行添加-e,可以输出错误栈信息 3)Profiles填写hadoop-2 dist,相当于-Phadoop-2,dist(如上图) 运行报错: Caused by: java.io.IOException: Cannot run program "bash" (in directory "F:\IdeaProjects\hive-1.1.0-cdh5.7.0\common"): CreateProcess error=2, 系统找不到指定的文件。这是因为在Windows环境不能执行bash。那么需要能执行bash环境,有一个神器:Git安装git后,打开Git Bash,即可在Windows系统中执行Linux命令了!cd到hive源码项目根目录,执行mvn -e clean package -Phadoop-2,dist -DskipTests=true 注意事项:需要配置Maven环境变量,并且一定要写%M2_HOME%而非%MAVEN_HOME%! 编译成功后,在项目根目录下的packaging/target下会生成tar包和一个同名文件夹,如下图。同名文件夹是这个tar包解压后的文件夹,上传到Linux可直接使用,免解压。

April 24, 2019 · 1 min · jiezi

ScalikeJDBC连接MySQL

ScalikeJDBC是一个Scala的JDBC框架,官网说easy-to-use and very flexible,易用又灵活~ 1、添加依赖 <dependency> <groupId>org.scalikejdbc</groupId> <artifactId>scalikejdbc_2.11</artifactId> <version>3.3.2</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.4.197</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.15</version> </dependency>2、上代码 import scalikejdbc._object MySQLDAO { def main(args: Array[String]): Unit = { // initialize JDBC driver & connection pool Class.forName("org.h2.Driver") ConnectionPool.singleton("jdbc:mysql:///film?characterEncoding=utf8", "root", "root") val id = 1 val name = "复联%" val value = sql"""select * from movie where name LIKE $name ORDER BY id DESC """ println(value) // simple example val lasts: List[Map[String, Any]] = DB.readOnly { implicit session => sql"""select * from movie where name LIKE $name ORDER BY id DESC """.map(_.toMap()).list.apply() } println(lasts) }}3、排错1)版本 ...

April 23, 2019 · 1 min · jiezi

len(x) 击败 x.len(),从内置函数看 Python 的设计思想

内置函数是 Python 的一大特色,用极简的语法实现很多常用的操作。 它们预先定义在内置命名空间中,开箱即用,所见即所得。Python 被公认是一种新手友好型的语言,这种说法能够成立,内置函数在其中起到了极关键的作用。 举个例子,求字符串 x 的长度,Python 的写法是 len(x) ,而且这种写法对列表、元组和字典等对象也同样适用,只需要传入对应的参数即可。len() 函数是共用的。 这是一种极简哲学的体现:Simple is better than complex。 但是,有些语言并不是这样,例如在 Java 中,字符串类有一个求长度的方法,其它类也有自己的求长度的方法,它们无法共用。每次使用时,通过类或实例来调用。 同样是求字符串长度,Python 的写法: saying = "Hello world!"print(len(saying))# 结果:12而在 Java 中,写法可能如下(简化起见): String saying = "Hello world!";System.out.println(saying.length());// 结果:12Python 采用的是一种前缀表达式 ,而 Java 采用的则是后缀表达式 。 除了求长度,Python 的某些内置函数也能在 Java 中找到对应的表达。例如,数值型字符串 s 转化为整型数字,Python 可以用 int(s) 函数,而 Java 可以用 Integer.parseInt(s) ;整型数字转化为字符串,Python 可以用 str(i) ,而 Java 也有 String.valueOf(i) 。 Python 的内置函数不与特定的类绑定,它们是一级对象。而 Java 的“函数”则无法脱离类而存在,它们只是附属品。 从直观角度来看,Python 的表达似乎是更优的。但是,它们并不具有可比性 ,因为这是两套语言系统,各有独特的范畴背景,并不能轻易地化约。 ...

April 21, 2019 · 2 min · jiezi

在 IntelliJ IDEA 中部署应用到服务器(Eclipse)

在之前的文章《在 Intellij IDEA 中部署 Java 应用到 阿里云 ECS》中讲解了如何将一个本地应用部署到阿里云 ECS 上去,有些读者反馈目前还有一些测试机器是在经典网络,甚至是在本地机房中,咨询是否可以通过 Cloud Toolkit 插件将应用部署到这些服务器上去?最新版本的 Cloud Toolkit 已经发布,完全支持啦。本地开发无论是编写云端运行的,还是编写本地运行的 Java 应用程序,代码编写本身并没有特别大的变化,因此本文采用一个及其基础的样例《在 Web 页面打印 HelloWorld 的 Java Servlet 》为例,做参考。public class IndexServlet extends HttpServlet { private static final long serialVersionUID = -112210702214857712L; @Override public void doGet( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); //Demo:通过 Cloud Toolkit ,高效的将本地应用程序代码修改,部署到云上。 writer.write(“Deploy from alibaba cloud toolkit. 2018-10-24”); return; } @Override protected void doPost( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException { return; }}源代码下载上述代码就是一个标准的 Java 工程,用于在 Web 页面上打印一串“Hello World”的文案。安装插件阿里云提供了基于 Intellij IDEA 的插件,以方便开发人员能够高效的将本地 IDE 中编写的应用程序,极速部署到服务器中去。插件主页:https://www.aliyun.com/product/cloudtoolkit阿里云的这个 IntelliJ IDEA 插件的安装过程,和普通的插件大同小异,这里不再赘述,读者请自行安装。添加服务器如上图所示,在菜单 Tools - Alibaba Cloud - Alibaba Cloud View - Host中打开机器视图界面,如下图:点击右上角Add Host按钮,出现添加机器界面部署在 IntelliJ IDEA 中,鼠标右键项目工程名,在出现的菜单中点击 Alibaba Cloud - Deploy to Host…,会出现如下部署窗口:在 Deploy to Host 对话框设置部署参数,然后单击 Deploy,即可执行初次部署。部署参数说明:Deploy File:部署文件包含两种方式。Maven Build:如果当前工程采用 Maven 构建,可以使用 Cloud Toolkit 直接构建并部署。Upload File:如果当前工程并非采用 Maven 构建,或者本地已经存在打包好的部署文件,可以选择并直接上传本地的部署文件。Target Deploy host:在下拉列表中选择Tag,然后选择要部署的服务器。Deploy Location :输入在 ECS 上部署路径,如 /root/tomcat/webapps。Commond:输入应用启动命令,如 sh /root/restart.sh。表示在完成应用包的部署后,需要执行的命令 —— 对于 Java 程序而言,通常是一句 Tomcat 的启动命令。本文作者:银时阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

April 18, 2019 · 1 min · jiezi

springboot实战(一)

最近在看《JavaEE开发的颠覆者 Spring Boot实战》,顺便写了一个小框架,在这里作为记录,供以后回顾github:源码地址当前进度描述core 核心模块aop定义(aop包)日志切面异常切面抽象(base包)controller抽象,封装返回结果对象|controler异常通知器service抽象,为业务模块提供通用的业务逻辑,如增、删、改、查等mapper抽象,为业务模块提供通用的持久化逻辑,如增、删、改、查等。通过反射技术结合Mybatis的注解,提供通用的SQLentity抽象,定义通用的字段,如创建人、创建时间、修改人、修改时间、删除标识等通用工具Spring上下文工具Spring属性文件工具配置Http请求过滤器条件注入,根据配置文件中定义的spring.http.encoding的配置,动态创建CharacterEncodingFilter通用配置druid数据源、监视器配置动态数据源注册器 引入bean扫描目录的定义,扫描范围是com.wt 下属的所有包多数据源(datasource包)核心代码是DynamicDataSource,通过继承Springboot提供的DynamicDataSource,来实现多数据源定义了aop切面DynamicDattaSourceInterceptor,拦截方法调用,发现有指定的@TargetDataSource注解,就会将当前线程的数据源指定为注解指定的数据源多数据源相关的配置类,利用了Springboot的动态配置特性,定义spring.factories文件指定DynamicDataSourceConfiguration配置类,根据配置文件中的slave.enable的值决定是否加载动态数据源的相关配置反射工具j2ee 依赖管理,添加必要的web项目依赖root maven构建方式定义version 管理依赖的版本

April 15, 2019 · 1 min · jiezi

在不同的 git 分支中统一 pom.xml 的版本号

在 Maven 项目和 git 配合使用时,有时候不同的分支会需要用不同的版本。举个例子:首先分支 A 中使用 <version>1.0-A-SNAPSHOT</version>,然后在其基础上创建分支 B,在分支 B 中修改了 pom.xml,使用 <version>1.0-B-SNAPSHOT</version>。之后当需要从 B 合并到 A 时,就会发现 pom.xml 的修改也合并过来了,使得 A 分支变成了 <version>1.0-B-SNAPSHOT</version>。这当然令人不爽。下面介绍一个 Maven 插件,允许你将当前分支作为变量放入 <version> 元素。只要在 pom 的 <build> -> <plugins> 中加入以下插件:<plugin> <groupId>pl.project13.maven</groupId> <artifactId>git-commit-id-plugin</artifactId> <version>2.2.6</version> <executions> <execution> <id>get-the-git-infos</id> <goals> <goal>revision</goal> </goals> <phase>initialize</phase> </execution> <execution> <id>validate-the-git-infos</id> <goals> <goal>validateRevision</goal> </goals> <phase>package</phase> </execution> </executions></plugin>插件的最新版本在这里查看。之后不论你在哪个分支,都可以统一用下面的版本号了:<version>${git.branch}</version>

April 13, 2019 · 1 min · jiezi

hadoop-2.6.0-cdh5.7.0源码编译支持压缩

在hadoop-2.6.0-cdh5.7.0源码中有个BUILDING.txt文件,里面列出了编译所需依赖组件。Requirements:Unix SystemJDK 1.7+Maven 3.0 or laterFindbugs 1.3.9 (if running findbugs)ProtocolBuffer 2.5.0CMake 2.6 or newer (if compiling native code), must be 3.0 or newer on MacZlib devel (if compiling native code)openssl devel ( if compiling native hadoop-pipes )Internet connection for first build (to fetch all Maven and Hadoop dependencies)转载链接文章中或通过yum安装或通过自己下载提供了所有正确版本组件,并将已下载组件通过百度云分享。我想补充一点的是,yum安装可能报出Another app is currently holding the yum lock; waiting for it to exit…的错误,可参考https://blog.csdn.net/testcs_…强制关闭yum进程来解决。根据BUILDING.txt提示Build options:Use -Pnative to compile/bundle native code * Use -Pdocs togenerate & bundle the documentation in the distribution (using -Pdist)Use -Psrc to create a project source TAR.GZ * Use -Dtar to create a TAR with the distribution (using -Pdist)Building distributions:Create binary distribution without native code and withoutdocumentation:$ mvn package -Pdist -DskipTests -DtarCreate binary distribution with native code and with documentation:$ mvn package -Pdist,native,docs -DskipTests -Dtar使用mvn clean package -Pdist,native -DskipTests -Dtar编译,编译完成后,默认会在源码根目录的hadoop-dist目录下生成target,里面的hadoop-2.6.0-cdh5.7.0文件夹就是已经编译好并已解压的hadoop了(直接用的),可以将其拷贝到自定义的位置进行部署配置。[root@NN1 hadoop-2.6.0-cdh5.7.0]# ./bin/hadoop checknative19/04/10 11:22:34 INFO bzip2.Bzip2Factory: Successfully loaded & initialized native-bzip2 library system-native19/04/10 11:22:34 INFO zlib.ZlibFactory: Successfully loaded & initialized native-zlib libraryNative library checking:hadoop: true /root/hadoop-c/hadoop-2.6.0-cdh5.7.0-target/hadoop-2.6.0-cdh5.7.0/lib/native/libhadoop.so.1.0.0zlib: true /lib64/libz.so.1snappy: true /lib64/libsnappy.so.1lz4: true revision:99bzip2: true /lib64/libbz2.so.1openssl: true /lib64/libcrypto.so可以看到编译的hadoop支持了各种压缩,亲测有效! ...

April 10, 2019 · 1 min · jiezi

基于jenkins搭建CICD

本文主要介绍通过jenkins参数化构建搭建CICD(持续集成/持续交付),主要介绍jenkins参数化构建配置,jenkins本身搭建请查看官方文档涉及到的插件:description setter plugin 、user build vars plugin、qunar plugin一、最终效果二、参数化配置点击配置,勾选参数化构建点击添加参数,有下面这些参数

April 8, 2019 · 1 min · jiezi

IntelliJ IDEA创建Spring Boot项目

File–>New–>Project选择Spring Initializrmaven参数Group组织唯一标识(组织域名倒序)Artifact项目的唯一标识输出格式jar/warjdk版本开发语言javaVersion目前项目版本选择依赖项目名称目录结构创建controller,service,pojo包编写DemoController@RestControllerpublic class DemoController { @GetMapping(“demo-method”) public String demoMethod() { return “success”; }}启动访问http://127.0.0.1:8080/demo-method

April 8, 2019 · 1 min · jiezi

使用maven创建简单的多模块 Spring Web项目

第一次写技术文章,主要内容是使用maven创建一个简单的SpringMVC WEB 项目,如有操作或理解错误请务必指出,当谦虚学习。做这一次的工作主要是因为想加强一下自己对Spring Web 项目的理解,因为平时都是直接写业务代码,我觉得还是有必要自己了解一下创建项目的过程。后续会基于这个项目写更多的SpringWeb开发过程,希望能帮助到有需要的人。总的来说是一个相当精简的多模块springWeb项目搭建过程,让我们进入正题吧我们知道单体应用,就写在一个project里面的话,业务一旦庞大起来非常难以管理。把各个模块单独抽出来可以方便的对jar包进行版本管理(尽管我还没经历过这个),维护项目,团队开发也会方便许多。基本思想其实就是一个java web项目引用别的模块Jar包,最终web项目被打成war包发布。而所有的war包项目,jar包项目都是在同一个父模块下管理的(它们都是Maven项目)(如果你有IDE,装好插件就用IDE创建吧,我个人不喜欢手动命令行创建)1. 创建父项目下图中:框起来打勾这个会让你跳过项目模式选择,勾选对于创建项目没有什么影响,以后也许会转一下Maven这方面的文章POM包才能做父项目,谨记!!!!! 2. 子项目结构和创建以下是我的结构分层,你也可以按你的想法来,最终目的是要方便自己开发。test_parent (父项目) |—-test_web (web项目) |—-test_service (业务内容) |—-test_framework (工具,框架封装、配置) |—-test_dao (数据持久层,DO也放这) |—-test_controller (处理映射) 创建子项目直接右键父项目然后新建maven module ,也就是子模块我们先创建web模块,这里你可以勾选第一条然后创建简单项目,如果没有勾选,那么你要在下一步里选择 maven-achetype-webapp,这里以简单项目为例子Group Id 和 version 都是继承父项目的一定要选择war包打包,不然要重新把他构建成web项目。如果你没选war包:https://www.cnblogs.com/leonk…最后点finish完成点击生成Web描述文件 (web.xml)这样就完成了Web模块的创建,剩下的其他项目都是同样的步骤创建,都是选择jar包,参考下图:3. 配置各模块的pom.xmlpom.xml记录所需的jar包,模块联系,包信息,打包参数等等信息,在多模块里我们要理清关系,不要重复引用首先毫无疑问的是让parent加载spring的jar包是最方便开发的,因为默认所有模块都继承parent,所以子模块引用spring内容也方便。其次配置文件我们统一放在framework中进行管理。那么先来写入web.xml配置吧<?xml version=“1.0” encoding=“UTF-8”?><web-app xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xmlns=“http://java.sun.com/xml/ns/javaee" xsi:schemaLocation=“http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id=“WebApp_ID” version=“3.0”> <display-name>test_web</display-name> <context-param> <!– 配置地址 –> <param-name>contextConfigLocation</param-name> <param-value>classpath*:spring-.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <!– spring-mvc.xml 配置地址 –> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/</url-pattern> </filter-mapping></web-app>这里可以看到我们写了classpath,原因是它能搜索到项目目录以外的Jar包下文件相关:http://www.cnblogs.com/wlgqo/…web.xml详解:https://blog.csdn.net/qq_3557…web.xml是对WEB项目来说是必须的配置文件,写好了spring配置文件的位置以后,就来新建2个spring配置文件,新建的配置放在test_framework模块里,路径如下图 spring-context.xml spring-mvc.xml一个是spring-context.xml 也叫applicationContext.xml,是webApp的上下文配置,也可以理解为配置dao、service 通用bean的地方,但我们这里使用的是注解扫描方式配置bean,所以就简单许多,即便有工具存在,写改xml真的很讨厌啊!<?xml version=“1.0” encoding=“UTF-8”?><beans xmlns=“http://www.springframework.org/schema/beans" xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc=“http://www.springframework.org/schema/mvc" xmlns:context=“http://www.springframework.org/schema/context" xmlns:tx=“http://www.springframework.org/schema/tx" xmlns:util=“http://www.springframework.org/schema/util" xmlns:aop=“http://www.springframework.org/schema/aop" xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <!– 注解注册 –> <!– <context:annotation-config /> –> <context:component-scan base-package=“com.test” > <context:exclude-filter type=“annotation” expression=“org.springframework.stereotype.Controller” /> <context:exclude-filter type=“annotation” expression=“org.springframework.web.bind.annotation.RestController” /> </context:component-scan> </beans>这里要去掉对controller的扫描,applicationContext初始化的上下文加载的Bean是对于整个应用程序共享的,不管是使用什么表现层技术,一般如DAO层、Service层Bean; DispatcherServlet (下一个要配置的东西) 初始化的上下文加载的Bean是只对Spring Web MVC有效的Bean,如Controller、HandlerMapping、HandlerAdapter等等,该初始化上下文应该只加载Web相关组件。context:component-scan 的 base-package 值用来决定我们需要扫描的包的基础名,具体配置相关可以看:https://www.cnblogs.com/exe19…而context:annotation-config/ 呢?其实也是spring为了方便我们开发者给我们提供的一个自动识别注解的配置,相关细节如下:解释说明:https://www.cnblogs.com/_popc…两条配置的区别和诠释:https://www.cnblogs.com/leiOO…下面是第二个配置文件 spring-mvc.xml<?xml version=“1.0” encoding=“UTF-8” standalone=“no”?><beans xmlns=“http://www.springframework.org/schema/beans" xmlns:context=“http://www.springframework.org/schema/context" xmlns:aop=“http://www.springframework.org/schema/aop" xmlns:mvc=“http://www.springframework.org/schema/mvc" xmlns:p=“http://www.springframework.org/schema/p" xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <!– 自动扫描的包名 –> <context:component-scan base-package=“com.test.*.controller” > <context:include-filter type=“annotation” expression=“org.springframework.stereotype.Controller” /> </context:component-scan> <!– 默认的注解映射的支持 –> <mvc:annotation-driven> <mvc:message-converters> <bean class=“org.springframework.http.converter.StringHttpMessageConverter”> <constructor-arg value=“UTF-8” /> </bean> <bean class=“org.springframework.http.converter.ResourceHttpMessageConverter” /> </mvc:message-converters> </mvc:annotation-driven></beans>包扫描没什么好说的,这里还强调include了注解controller。mvc:annotation-driven 是spring默认的注解驱动,这个配置项一口气把一堆东西都给我们加进来了,但主要还是针对controller和处理请求的,具体的在下面文章中,因为加的内容有点多,所以这个留到后面研究,稍微理解作用就好:相关文章 : https://blog.csdn.net/vicroad...mvc:message-converters 顾名思义,就是用于处理请求消息的,request content-header 会记录请求的内容类型,根据这些类型,spring会把内容转化成服务器操作的对象,这里的字符串转化是为了避免乱码,我们指定了编码格式。相关文章:https://www.jianshu.com/p/2f6…以上,我们就已经把最简约的配置写好了。接下来我们随便写一个controller试试4.写个Controller吧根据之前写好的controller的扫描包名,去我们test_controller模块里创建一个controllerpackage com.test.hello.controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/test”)public class HelloController{ @RequestMapping("/get”) public String helloGet(@RequestParam String str) throws Exception { return str; }}很简单的一段返回请求字符串的代码,现在一切就绪可以启动服务器了,配置好Tomcat就可以启动了,右键test_web –> run as –> run on server 选择创建好的tomcat容器,就可以启动了。接下来,访问: localhost:8080/test/test/get?str=helloWorld 如果你使用eclipse启动且没有正常启动,特别是出现严重错误时,请先检查web.xml配置命名有没有问题,然后再检查test_web项目的assembly,这个会影响项目的发布文件,下图所示,右键项目点properties,没有test_framework的话就加入framework项目。网站无响应,检查一下tomcat的端口,默认是8080。404检查代码的映射路径。5.结束语第一次写技术文章,记录一下自己的学习过程,日后会以当前项目作为基础,继续记录下自己遇到的问题和分享的知识,希望能帮助到一部分新手,此外,本篇文章中若有错误,欢迎指出,我会不断更新文章误点,不吝赐教。 ...

April 4, 2019 · 2 min · jiezi

Maven使用tips

Maven库Maven库:http://repo2.maven.org/maven2/Maven依赖查询: http://mvnrepository.com/Maven常用命令(1).创建Maven的Web项目:mvn archetype:create-DgroupId=packageName-DartifactId=webappName-DarchetypeArtifactId=maven-archetype-webapp(2). 编译源代码:mvn compile(3). 编译测试代码:mvn test-compile(4). 运行测试: mvn test(5). 产生site:mvn site(6). 打包:mvn package(7). 在本地Repository中安装jar:mvn install(8). 清除产生的项目:mvn clean(9). 生成eclipse项目:mvn eclipse:eclipse(10). 生成idea项目:mvn idea:idea(11). 组合使用goal命令,如只打包不测试:mvn -Dtest package(12). 编译测试的内容:mvn test-compile(13). 只打jar包:mvn jar:jar(14). 只测试而不编译,也不测试编译:mvn test -skipping compile -skipping test-compile ( -skipping 的灵活运用,当然也可以用于其他组合命令) (15). 清除eclipse的一些系统设置:mvn eclipse:clean (16).查看当前项目已被解析的依赖:mvn dependency:list(17).上传到私服:mvn deploymvn compile与mvn install、mvn deploy的区别mvn compile,编译类文件mvn install,包含mvn compile,mvn package,然后上传到本地仓库mvn deploy,包含mvn install,然后,上传到私服

April 2, 2019 · 1 min · jiezi

详解服务器端的项目框架

导读我一直相信这句话,他山之石可以攻玉。在自己能力不够时,多学习别人的东西。这样,对自己只有好处,没有坏处。因而,经过将近一年的工作,研读了公司所使用的框架。我本想往架构师的方向靠近,但,自己的能力可能还不够,因而,不断地给自己充电。公司的项目是前后端分离的,前端使用HTML5,css3、jquery、vue.js、bootstrap等,以SVN做代码托管。后端采用maven构建项目,以git lab做代码托管。肯定有人会问,这两个都是版本库,但它们有什么区别?如果想要了解的话,可以参考该文档:Svn与Git的区别。现在几乎所有的公司都采用maven构建项目,很少会采用导入jar包的方式依赖第三方框架。maven介绍maven构建的项目有很多好处,首先其可以统一管理jar包,也就是说,我们在项目中不用手动导入jar包,我们只要添加依赖即可,如代码所示:<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${jdbc.version}</version></dependency>添加依赖之后,maven就会导入该jar包,导入jar包的顺序为:首先查找本地仓库,如果本地仓库没有,进入下面步骤。maven settings profile中的repository;pom.xml中profile中定义的repository。profile激活配置文件,比如正式环境的配置文件prd.properties和开发环境的Dev.properties文件。这也是打包的依据,是打开发环境的包,还是打正式环境的包,如图所示:pom.xml中的repositorys(定义多个repository,按定义顺序找);如果经过上面的步骤,没有找到相应的jar包,最后到我们的镜像(mirror)中查找。如果mirror中存在该jar包,从mirror中拷贝下来,存储到本地仓库中,进入到最初一步。如果mirror中也没有,maven就会报相应的错误。maven报出相应的错误时,也许,是我们本地没有该jar包,远程仓库也没有该jar包,我们可以参考这篇博客:在maven的pom.xml中添加本地jar包。它会教你如何创建本地仓库,并导入创建好的本地仓库。【备注】这篇博客以架构师的角度来讲解maven,所以,不具体讲解maven各个标签的含义。如果你想了解pom的各个标签的含义,可以参考这篇文档:pom.xml详解,或者,参考这篇教程:maven教程|菜鸟教程上面解说只是配置jar文件,但是,maven的功能远不止这些,从我们创建maven项目时,就已经进入到maven的开发环境中。maven项目有人和我说过,学一项知识,什么方式最快?那就是通过做项目。你在做项目的过程中,肯定会遇到很多问题,而你不得不去查找资料,从根源上认识到这个问题。因而,我以公司所做的某个项目为例,来讲解maven的依赖、继承、聚合等关系。我们所说的maven中的关系,其实就是pom的关系,即项目对象模型(Project Object Model)的简称。maven聚合首先,我们在创建cloudCodeSale项目时,就已经创建了父pom文件,如图所示:上图就是我们的父pom文件,你很清楚的看到gav坐标。同时,你从这张图上,也能得到其他信息,其打包方式是 pom,其还关联其他module,module名称和左边的列表名称一样。这就是我们所说的maven的聚合。父类同时聚合其子类。聚合的条件有两个:修改被聚合项目的pom.xml中的packaging元素的值为pom在被聚合项目的pom.xml中的modules元素下指定它的子模块项目既然所有的子模块的pom都继承父pom,为什么父pom要聚合子模块的pom文件?这个问题很好。因为对于聚合而言,当我们在被聚合的项目上使用Maven命令时,实际上这些命令都会在它的子模块项目上使用。这就是Maven中聚合的一个非常重要的作用。在实际开发的过程中,我们只需要打包(mvn install)父pom文件。我们在父pom上使用mvn celan、mvn compile和mvn package,其会自动对子模块:platform-core、platform-core-controller、portal/member-portal、portal/platform-portal、platform-cms、platform-cms-controller、platform-custom执行mvn celan、mvn compile和mvn package。没必要一个一个地打包,这样极容易出现错误,如图所示:maven继承机制如果很多模块都需要相同的jar包,我们可以单独写在一个pom中,其他模块使用该模块的公共部分,这就是我们常说的父类。不论是java语言,还是c++语言,或者现在的pom,其都体现这个思想。我们在上文也提到了子模块,现在模块platform-core讲解。继承父类的结构一般是这样的:<parent> <groupId>parent.groupId</groupId> <artifactId>parent.artifactId</artifactId> <version>parent.version</version> <relativePath>../pom.xml</relativePath> </parent> relativePath是父pom.xml文件相对于子pom.xml文件的位置,针对被继承的父pom与继承pom的目录结构是不是父子关系。如果是父子关系,则不用该标签;如果不是,那么就用该标签。因为在当前项目中,platform-core模块的目录的pom在父目录的pom中,其和父pom的目录结构是父子关系,因而可以省略relativePath该标签,如图所示:parent标签中的groupId、artifactId、version要和父pom中的标签中一致。maven的依赖关系正如我们所知道的,maven构建项目,不仅是因为其能够管理jar包,其还使模块化开发更简单了。因而,我们在开发的过程中,一般都分模块化开发。模块与模块之间的信息是不通的,但是,我们想要模块间的之间能够通信,这时,我们就想到了java中的依赖关系。比如,我们有一个模块,这个模块封装好了微信支付、支付宝支付、处理json格式、操作文件、ResultUtil、lambdaUtil、commonUtil等工具类,还有附件、头像、用户等实体类。这些工具类在任何项目中不会轻易改变,如果为了满足某些需求而不得不得修改,需要得到架构师的同意。因而,我们可以把它拿出来,单独定义为一个模块,也就是platform-core模块。但是,我们还有一个模块,在这个模块中,根据不同的项目,其定义不同的实体类、dao层类、事务层类、枚举类、接收前端传来参数封装成的query类、从数据库中取出的数据封装成的data类,到事务层可能会调用模块plateform-core中的方法,比如调用第三方系统接口的HTTPClientUtil.doPost(String url, Map<String, String> param),判断处理lambda表达式的LambdaUtil.ifNotBlankThen(String value, Consumer<String> function) ,等等。这个自定义类的模块,我们可定义为plateform-custom。plateform-custom需要用到platform-core中的方法,因而,这时,我们就需要考虑依赖关系,怎么添加对platform-core的依赖呢?如代码所示:<dependency> <groupId>com.zfounder.platform</groupId> <artifactId>platform-core</artifactId></dependency>我们这边是前后台分离的,后台用来录入数据,前台用来展示数据,因而,我们有一个portal目录,该目录下有两个子模块。一个是member-portal模块,一个是platform-portal模块,前者接收前台的接口参数,后者接收后台的接口参数。但不论哪个模块,都需要依赖plateform-custom中的事务层方法,同时,我们传的参数,可能信息分发的platform-cms-controller中的接口,也可能是核心接口platform-core-controller中的接口。因而,我们这里以member-portal模块来举例,依赖其他模块的代码如下:<dependencies> <dependency> <groupId>com.zfounder.platform</groupId> <artifactId>platform-core-controller</artifactId> </dependency> <dependency> <groupId>com.zfounder.platform</groupId> <artifactId>platform-cms-controller</artifactId> </dependency> <dependency> <groupId>com.zfounder.platform</groupId> <artifactId>platform-custom</artifactId> <version>1.0-SNAPSHOT</version> </dependency></dependencies>这些模块你会在上面的图片找得到。同时,我们来看member-portal的pom文件继承的父pom是怎么写的:补充上面的继承关系。这里面用到了<relativePath>../../pom.xml</relativePath>你会奇怪的是,为什么这里面用到了呢?其和父pom不是父子关系,而是孙子关系。这里使用到了两次点点,这是什么意思呢? ..表示上级目录。举个例子说明:比如,在我的服务器上的www目录中,有三个文件,分别是rsa_private_key.pem, rsa_private_key_pkcs8.pem, rsa_public_key.pem,还有一个testDir目录,testDir目录中还有目录testDir,现在我们通过cd ../testDir/testDir进入到子目录中,现在,我们想返回到www的根目录中,并查看rsa_public_key.pem文件的内容,因而,我们可以用cat ../../rsa_public_key.pem命令,其首先返回两级目录,然后找到rsa_public_key.pem文件并打开该文件。“被继承的父pom与继承pom的目录结构是不是父子关系”也不是绝对的,主要是选择继承者的pom中的子目录和父目录之间的关系,其中间隔了几层目录。maven激活文件激活文件在上文也提到了,我们为什么需要激活文件?如下面的两个配置文件,一个是测试环境的配置文件,名为platform-dev.properties,一个是正式环境的配置文件,名为platform-prd.properties。两个配置文件中都存在与数据库的连接,但是呢,数据库的ip地址是不一样的。如一下的代码所示:正式服的platform-prd.properties配置文件jdbc.url=jdbc:mysql://localhost/prd_databasejdbc.username=prd_usernamejdbc.password=prd_passwordjdbc.validationQuery=select 1 from dualjdbc.removeAbandonedTimeout=180jdbc.initialSize=10jdbc.minIdle=30jdbc.maxActive=100jdbc.maxWait=30000。。。测试服的platform-dev.properties配置文件jdbc.url=jdbc:mysql://intranet_ip/dev_databasejdbc.username=dev_usernamejdbc.password=dev_passwordjdbc.validationQuery=select 1 from dualjdbc.removeAbandonedTimeout=180jdbc.initialSize=10jdbc.minIdle=30jdbc.maxActive=100jdbc.maxWait=30000。。。我们的在配置文件中配置好了数据项,但是呢,我们怎么切换不同的配置文件呢?换句话说,我们怎么想要打正式服的包放到正式服上,怎么选择platform-prd.properties的配置文件呢?反之,怎么选择platform-dev.properties配置文件?这时,我们就用到了maven当中的profile标签,如下代码所示: <profiles> <profile> <id>dev</id> <activation> <activeByDefault>true</activeByDefault> </activation> <build> <filters> <filter>../../platform-dev.properties</filter> </filters> </build> </profile> <profile> <id>prd</id> <build> <filters> <filter>../../platform-prd.properties</filter> </filters> </build> </profile></profiles>这些配置文件时写在member-portal、platform-portal、plateform-core和plateform-cms、plateform-customer模块的pom中的。但是,plateform-core和plateform-cms的配置中的filter和上面连个略有差异,其filter是这样的 <filter>../platform-dev.properties</filter>和 <filter>../platform-prd.properties</filter>,这就涉及到目录点的问题。maven依赖第三方包maven项目除了依赖本项目的,其还会依赖第三方包,比如自动生成set和get方法的lombok包,处理json格式的阿里巴巴下的fastjson包等等,我们也可以使用这种格式的依赖:<!–mysql jdbc驱动包 开始–><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${jdbc.version}</version></dependency><!–mysql jdbc驱动包 结束–>开发常用的jar包lombok<!– lombok驱动包 开始–><dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version></dependency><!– lombok驱动包 开始–>我们在没有使用lombok之前,经常手动创建javabean的set个get方法,使用这个框架之后,其以注解的方式,可以自动生成set和get方法。同时,其强大的功能远不止这些,也可以生成无参构造器、全参构造器,指定参数构造器、重写toString方法、重写Hashcode、equals方法等等。如代码所示:/** * Created By zby on 17:37 2019/1/30 /@AllArgsConstructor@NoArgsConstructor@Data@ToString@EqualsAndHashCodepublic class Address { /* * 收货人 / private String consignee; /* * 手机号码 / private String phone; /* * 所在地区 / private String area; /* * 详细地址 / private String detail; /* * 标签 / private AddressTagEnum addressTag;}想要更深层次的了解这个框架,可以参考这个博客:Lombok使用详解fastjson<!– fastjson驱动包 开始–><dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.28</version></dependency><!– fastjson驱动包 结束–>fastjson是阿里巴巴开源的框架,其用来处理服务器端的json格式的数据。比如,我们需要将服务端的对象以json(JavaScript object Notation,js对象标记)格式传输到前端,但是,如果自己手动创建的话,势必会非常的麻烦,于是,我们借助这个框架,帮助我们生成json格式的对象。同时,如果我们要调用第三方接口,比如调用连连绑定银行卡的接口,其返回给我们的也是json对象的数据。但是,我们需要将其转化为我们定义的对象,调用其save方法,保存到数据库中,对账所用。对于,将对象转化为json格式的对象,如代码所示:@Testpublic void test() {// 地址 Address address = new Address(); address.setAddressTag(AddressTagEnum.ADDRESS_TAG_COMPANY); address.setArea(“杭州市….”); address.setConsignee(“zby”);// 用户 User user = new User(); user.setHobby(HobbyEnum.HOBBY_DANCING); user.setGender(“男”); user.setUserName(“蒋三”);// 订单 OrderSnapshot orderSnapshot = new OrderSnapshot(); orderSnapshot.setAddress(address); orderSnapshot.setId(1L); orderSnapshot.setName(“复读机”); orderSnapshot.setOrderNo(Long.valueOf(System.currentTimeMillis()).toString() + “1L”); orderSnapshot.setUser(user); System.out.println(JSON.toJSON(orderSnapshot));}其输出结果如图所示:但是,类似于解析json格式的数据,不只有fastjson框,还有org.json框架、Jackson框架。但经过有人验证呢,还是fastjson的效率更高一些。可以参考这篇博客:Gson、FastJson、org.JSON到底哪一个效率更高,速度更快org.json也是通过maven配置的,如代码所示:<!– json驱动包 开始–><dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20140107</version></dependency><!– json驱动包 开始–>如果想要深层次了解org.json,可以参考这篇博客:Java使用org.json.jar构造和解析Json数据想要更深层次的了解fastjson,可以参考这篇博客:Fastjson 简明教程spring相关配置如果从事java-web开发,一般会用到spring框架,这方面的教程太多了,笔者就不在这介绍,但我们会用到spring的这些框架:<!–spring 相关配置开始–><dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId></dependency><dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId></dependency><dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId></dependency><dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId></dependency><dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId></dependency>spring会集合很多框架,比如具有拦截效果的shiro框架,持久层的hibernate和mybatis框架等等。spring通过配置文件通过注解或者配置文件的方式,实现依赖注入(dependency injection)和控制反转(inversion of control)。通过@controller遍历相应的接口,实现前后端的接口对接。spring可以实现面向切面编程,实现某个业务点的单一执行。比如,专门处理事务的业务点。spring并不难,很快就能掌握到其精髓。如果想深入了解,可以参考这篇教程:Spring教程hibernate框架hibernate框架就类似于mybatis框架,其专门处理持久层的技术。我们将瞬时状态的对象存储到数据库中,变成持久状态的对象。我们也可以从数据库中取数据,以瞬时态的对象返回到前端。这就是一存一取的框架。其可以使用注解的方式创建数据表,也可以通过配置文件创建瞬时态的对象。但就目前为止,在很多情况下,我们都是通过注解的方式,实现数据表的创建。导入hibernate相关的框架,如下所示:<!–hibernate相关配置 开始–><!–hibernateh核心框架–><dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId></dependency><!–hibernateh验证器–><dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId></dependency><!–hibernateh缓存技术–><dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId></dependency> <!–Java Persistence API ORM映射元数据 查询语言–><dependency> <groupId>org.hibernate.java-persistence</groupId> <artifactId>jpa-api</artifactId></dependency><!–hibernate相关配置 结束–>hibernate和mybatis具有同样的功能,如果想要了解mybatis,可以参考这篇教程:mybatis教程想要深入理解hibernate,可参考这篇教程:hibernate教程_w3cschooljbdc驱动包我们上面说了hibernate框架,但前提是,我们需要导入jdbc的框架包,如代码所示: <!– 数据库驱动包相关 开始–><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId></dependency><!– 数据库驱动包相关 结束–>这个驱动包主要处理java与数据库的连接,实现数据的增、删、改、查。我们没有用到这个包,但是hibernate用到了这个包,因而,我们需要导入这个包,以免数据库报错。alibaba的Druid包这个包有什么用吗?我们既然通过hibernate实现与数据库的交互,那么就需要在初始化时创建连接池。现在连接池有很多种,我们为什么选择了它Druid。<!– Druid驱动包相关 开始–><dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId></dependency><!– Druid驱动包相关 结束–>它是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。Druid是阿里巴巴开发的号称为监控而生的数据库连接池!时代在变化,我们也应该应世而生,与时俱进,才不会和时代脱轨。我们使用Druid来实现数据的配置,如代码所示: <bean id=“dataSource” class=“com.alibaba.druid.pool.DruidDataSource” init-method=“init” destroy-method=“close”> <property name=“driverClassName” value=“com.mysql.jdbc.Driver”/> <property name=“url” value="${jdbc.url}"/> <property name=“username” value="${jdbc.username}"/> <property name=“password” value="${jdbc.password}"/> <property name=“maxActive” value="${jdbc.maxActive}"/> <property name=“initialSize” value="${jdbc.initialSize}"/> <property name=“removeAbandoned” value=“true”/> <property name=“removeAbandonedTimeout” value="${jdbc.removeAbandonedTimeout}"/> <property name=“testOnBorrow” value=“true”/> <property name=“minIdle” value="${jdbc.minIdle}"/> <property name=“maxWait” value="${jdbc.maxWait}"/> <property name=“validationQuery” value="${jdbc.validationQuery}"/> <property name=“connectionProperties” value=“clientEncoding=UTF-8”/></bean>你们可以看到,value值是形参,而不是具体的值。因为我们根据不同的打包方式,其传入形参对应的实参不同。这也就是我们上文提到的,platform-dev.properties和platform-prd.properties配置文件,以及maven配置的激活文件。如果想要深入了解阿里巴巴的Druid框架,可以参考这篇博客:DRUID连接池的实用 配置详解阿里云短信短信业务一般固定不变,由架构师封装好,其他人直接调用即可,因而,该框架可以写进plateform-core模块中,其配置的代码如下所示:<!– 阿里短息驱动包配置 开始 –><dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-dysmsapi</artifactId></dependency><dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId></dependency><!– 阿里短息驱动包配置 结束 –>日志相关配置我们在开发的过程中,经常会使用到日志,来记录相应的错误、警告、信息。比如,我在使用连连支付做提现业务时,提现成功后其会回调我们的接口,从而显示在服务端的Tomcat页面中。再比如,我们在登录时,其会在Tomcat中显示相关信息,如图所示:我们都知道日志分为几种级别。这里就不再赘述了。日志分为好多种,我们推荐使用slf4j+logback模式。因为logback自身实现了slf4j的接口,无须额外引入适配器,另外logback是log4j的升级版,具备比log4j更多的优点,我们可以通过如下配置进行集成:<!– 日志驱动包配置 开始 –><dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.21</version></dependency><dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.7</version></dependency><dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.7</version></dependency><!– 日志驱动包配置 结束 –>我们这时就用到了plateform-prd.properties文件和plateform-dev.properties文件,因为,我们需要在这里面配置日志的输出位置。然后,在logback.xml中以参数的形式,调用文件中的输出位置,如图所示:如果想要了解更多的配置文件信息,请参考这篇博客:使用 logback + slf4j 进行日志记录commons家族我们在开发的过程中,经常用到Commons家族的驱动包,比如文件操作的io包,MD5加密和解密用的codec包。当然,我们也会用到java自带的local_policy驱动包,但有时需要替换替换该驱动包,否则,就会报出Illegal Key Size的错误。文件上传下载的fileupload驱动包,操作字符串类型的lang3包,配置的驱动包如下所示:<!–comon包相关配置–><commons-io.version>2.4</commons-io.version><commons-lang3.version>3.4</commons-lang3.version><commons-codec.version>1.10</commons-codec.version><commons-fileupload.version>1.3.1</commons-fileupload.version><!– apache common 开始 –><dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>${commons-lang3.version}</version></dependency><dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>${commons-io.version}</version></dependency><dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>${commons-codec.version}</version></dependency><dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>${commons-fileupload.version}</version></dependency><!– apache common 结束 –>lang3包我们可以用其分割字符串,判断字符串是否为空格,判断字符串是否为空等等。如以下代码所示:public static void main(String[] args) { String keyword = “1-1-2”; if (StringUtils.isNotBlank(keyword)) { System.out.println(“keyword = " + keyword); } String[] keys = StringUtils.split(keyword, “-”); for (String key : keys) { System.out.println(“key=” + key); }}我们有时还会用其操作时间类,比如格式化时间等等,入一下代码:@Testpublic void testDate(){ String date1= FastDateFormat.getInstance(“yyyy-MM-dd”).format(System.currentTimeMillis()); System.out.println(“System.currentTimeMillis:"+date1); String date2= FastDateFormat.getInstance(“yyyy-MM-dd”).format(new Date()); System.out.println(“new Date:"+date2);}其功能远不止这些,具体可以参考这篇博客:commons-lang3工具包io包见名知意,IO即input和output的简写,即输入流和输出流。因而,我们经常使用到java自带的InputStream或FileInputStream的字节输入流,以及OutputStream或FileOutputStream的输出流。如果更高级的话,那么,就使用到了带有缓存效果的bufferReader输入流和bufferWrite输出流。这里面用到了装饰设计模式。什么是装修设计模式,可以自行学习。上面的操作比较复杂,我们就用到了apache下的io驱动包。这里就当做抛砖引玉了,想要有更深的了解,可以参考这篇博客:io包工具类codec包codec包是Commons家族中的加密和解密用的包,这里不做任何解释,具体可以参考这篇博客:Commons Codec基本使用fileupload包我们如果做java-web开发,经常会有文件上传和文件下载的功能。这时,我们就考虑到了Apache下面的 fileupload包,这可以完成文件的上传和下载。这里的文件不单单是指doc文件,也会指图片和视频文件。具体想要有更多的理解,可以参考这篇文档:commons-fileupload上传下载shiro包我们在web开发时,经常会涉及到权限问题,比如哪些页面不需要登录就能看,而哪些页面只能登录才能看。当用户在打开该页面之前,就进入到相应的过滤器中,来做相关业务的判断。如果通过,就进入到controller层;不通过,则抛出相应的异常给前端。这里就需要相应的权限控制。说到权限控制,我们不得不提到shiro框架。其有三大核心组件Subject, SecurityManager 和 Realms。这个百度百科上也说了,可以查看其解说内容:java安全框架 <!– shiro驱动包 开始 –><dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId></dependency><dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId></dependency><dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId></dependency><dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId></dependency><!–shiro驱动包 结束 –>公司也会做相应的配置,配置如下:<?xml version=“1.0” encoding=“UTF-8”?><beans xmlns:util=“http://www.springframework.org/schema/util" xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xmlns=“http://www.springframework.org/schema/beans" xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!– 缓存管理器 –> <bean id=“cacheManager” class=“com..shared.framework.SpringCacheManagerWrapper”> <property name=“cacheManager” ref=“springCacheManager”/> </bean> <bean id=“springCacheManager” class=“org.springframework.cache.ehcache.EhCacheCacheManager”> <property name=“cacheManager” ref=“ehcacheManager”/> </bean> <bean id=“ehcacheManager” class=“org.springframework.cache.ehcache.EhCacheManagerFactoryBean”> <property name=“configLocation” value=“classpath:ehcache.xml”/> </bean> <!– 凭证匹配器 –> <bean id=“credentialsMatcher” class=“com.*.RetryLimitHashedCredentialsMatcher”> <constructor-arg ref=“cacheManager”/> <property name=“hashAlgorithmName” value=“md5”/> <property name=“hashIterations” value=“2”/> <property name=“storedCredentialsHexEncoded” value=“true”/> </bean> <!– Realm实现 –> <bean id=“userRealm” class=“com..shared.web.listener.MemberSecurityRealm”> <!–<property name=“credentialsMatcher” ref=“credentialsMatcher”/>–> <property name=“cachingEnabled” value=“false”/> <!–<property name=“authenticationCachingEnabled” value=“true”/>–> <!–<property name=“authenticationCacheName” value=“authenticationCache”/>–> <!–<property name=“authorizationCachingEnabled” value=“true”/>–> <!–<property name=“authorizationCacheName” value=“authorizationCache”/>–> </bean> <!– 会话ID生成器 –> <!–<bean id=“sessionIdGenerator” class=“org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator”/>–> <!– 会话Cookie模板 –> <bean id=“sessionIdCookie” class=“org.apache.shiro.web.servlet.SimpleCookie”> <constructor-arg value=“platform-portal-sid”/> <property name=“httpOnly” value=“true”/> <property name=“maxAge” value=“7200”/> </bean> <!– 会话管理器 –> <bean id=“sessionManager” class=“org.apache.shiro.web.session.mgt.DefaultWebSessionManager”> <property name=“globalSessionTimeout” value=“43200000”/> <property name=“deleteInvalidSessions” value=“true”/> <property name=“sessionIdCookieEnabled” value=“true”/> <property name=“sessionIdCookie” ref=“sessionIdCookie”/> </bean> <!– 安全管理器 –> <bean id=“securityManager” class=“org.apache.shiro.web.mgt.DefaultWebSecurityManager”> <property name=“realm” ref=“userRealm”/> <property name=“sessionManager” ref=“sessionManager”/> <property name=“cacheManager” ref=“cacheManager”/> </bean> <!– 相当于调用SecurityUtils.setSecurityManager(securityManager) –> <bean class=“org.springframework.beans.factory.config.MethodInvokingFactoryBean”> <property name=“staticMethod” value=“org.apache.shiro.SecurityUtils.setSecurityManager”/> <property name=“arguments” ref=“securityManager”/> </bean> <!– Shiro的Web过滤器 –> <bean id=“shiroFilter” class=“org.apache.shiro.spring.web.ShiroFilterFactoryBean” depends-on=“securityManager,memberShiroFilerChainManager”> <property name=“securityManager” ref=“securityManager”/> </bean> <!– 基于url+角色的身份验证过滤器 –> <bean id=“urlAuthFilter” class=“com.zfounder.platform.core.shared.web.filter.UrlAuthFilter”> <property name=“ignoreCheckUriList”> <list> <value>//common/enums/</value> <value>//security/</value> <value>//common/dd/</value> <value>//pictures/</value> <value>//common/sms/</value> <value>//wx/</value> </list> </property> </bean> <bean id=“memberFilterChainManager” class=“com.zfounder.platform.core.shared.web.listener.CustomDefaultFilterChainManager”> <property name=“customFilters”> <util:map> <entry key=“roles” value-ref=“urlAuthFilter”/> </util:map> </property> </bean> <bean id=“memberFilterChainResolver” class=“com..shared.web.listener.CustomPathMatchingFilterChainResolver”> <property name=“customDefaultFilterChainManager” ref=“memberFilterChainManager”/> </bean> <bean class=“org.springframework.beans.factory.config.MethodInvokingFactoryBean” depends-on=“shiroFilter”> <property name=“targetObject” ref=“shiroFilter”/> <property name=“targetMethod” value=“setFilterChainResolver”/> <property name=“arguments” ref=“memberFilterChainResolver”/> </bean> <!– Shiro生命周期处理器–> <bean id=“lifecycleBeanPostProcessor” class=“org.apache.shiro.spring.LifecycleBeanPostProcessor”/></beans>想要对其有更深的理解,请参考这篇博客:Shiro讲解工具类<!–汉字转拼音开源工具包–> <dependency> <groupId>com.github.stuxuhai</groupId> <artifactId>jpinyin</artifactId></dependency><!–网络爬虫的驱动包–><dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId></dependency><!–验证码生成工具包–><dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId></dependency><!–发送邮件–><dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId></dependency>因为篇幅的限制,这里就不再细说了,如果想要更深层次的了解,可以参考以下博客:汉字转拼音开源工具包Jpinyin介绍爬虫+jsoup轻松爬知乎使用kaptcha生成验证码使用javax.mail发送邮件图片验证码的配置文件如下:<?xml version=“1.0” encoding=“UTF-8”?><beans xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xmlns=“http://www.springframework.org/schema/beans" xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" default-lazy-init=“true”> <bean id=“captchaProducer” class=“com.google.code.kaptcha.impl.DefaultKaptcha”> <property name=“config”> <bean class=“com.google.code.kaptcha.util.Config”> <constructor-arg> <props> <prop key=“kaptcha.border”>${kaptcha.border}</prop> <prop key=“kaptcha.border.color”>${kaptcha.border.color}</prop> <prop key=“kaptcha.textproducer.font.color”>${kaptcha.textproducer.font.color}</prop> <prop key=“kaptcha.textproducer.char.space”>${kaptcha.textproducer.char.space}</prop> <prop key=“kaptcha.textproducer.font.size”>${kaptcha.textproducer.font.size}</prop> <prop key=“kaptcha.image.width”>${kaptcha.image.width}</prop> <prop key=“kaptcha.image.height”>${kaptcha.image.height}</prop> <prop key=“kaptcha.textproducer.char.length”>${kaptcha.textproducer.char.length}</prop> <prop key=“kaptcha.textproducer.char.string”>1234567890</prop> <prop key=“kaptcha.textproducer.font.names”>宋体,楷体,微软雅黑</prop> <prop key=“kaptcha.noise.color”>${kaptcha.noise.color}</prop> <prop key=“kaptcha.noise.impl”>com.google.code.kaptcha.impl.NoNoise</prop> <prop key=“kaptcha.background.clear.from”>${kaptcha.background.clear.from}</prop> <prop key=“kaptcha.background.clear.to”>${kaptcha.background.clear.to}</prop> <prop key=“kaptcha.word.impl”>com.google.code.kaptcha.text.impl.DefaultWordRenderer</prop> <prop key=“kaptcha.obscurificator.impl”>com.google.code.kaptcha.impl.ShadowGimpy</prop> </props> </constructor-arg> </bean> </property> </bean></beans>里面的占位符来源于plateform-dev.properties或者plateform-prd.properties,这就是我们maven激活的配置文件的作用。测试依赖包我们在开发完一个功能后,首先会想到测试它走不走得通。我们可能会在main方法中测试,一个项目类中可以写多个main方法。如果每个功能类中都写一个main方法,未免会造成代码的混乱,一点都不美观和儒雅。java为什么一直推崇面向对象,任何在现实中真实的、虚拟的事物,都可以将其封装为为java中的对象类。对象与对象之间以方法作为消息传递机制,以属性作为数据库存储的机制。如果我们在每个功能中都写一个main方法,势必会破坏这种对象的美观性。因而,我们把测试的数据以对象的方式操作,这样,将其封装为一个测试包,比如,在我写的spring框架中,就把测试类单独拿出来,如图所示:<!– 测试依赖包 开始–><!– spring test –><dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version></dependency><!– 路径检索json或设置Json –><dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> <version>${jsonpath.version}</version> <scope>test</scope></dependency><!– testng –><dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>${testng.version}</version></dependency><!– 单元测试的powermock –><dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-testng</artifactId> <version>${powermock.version}</version></dependency><dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito</artifactId> <version>${powermock.version}</version></dependency><!–测试相关 结束–>以上是几种测试包的依赖,一个是spring的测试包,这里由于篇幅的限制,就不做详细的介绍了,网上有很多这方面的教程,想要深入的了解,可参考这篇博客:Spring-Test(单元测试)我们有时也会用到TestNG框架,它是Java中的一个测试框架,类似于JUnit 和NUnit,功能都差不多,只是功能更加强大,使用也更方便。测试人员一般用TestNG来写自动化测试,开发人员一般用JUnit写单元测试。如果你是测试人员,想对其有更全面的了解,可以参考这篇教程:TestNG教程,或者这篇博客::testNG常用用法总结如果想要更深层次的了解powermock,可以参考这篇博客:PowerMock从入门到放弃再到使用如果想要更深层次的了解JsonPath,可以参考这篇博客:JsonPath教程图片处理我们在开发的过程中,会把图片存放到服务器的某个文件夹下,即某个磁盘上。如果图片过大,会占用服务器的磁盘,因而,我们需要将图片缩略,来减少对内存的占用。这时,我们如果使用java原生的图片缩略图,是非常复杂的,因而,我们可以使用以下框架对图片进行操作。<!–图片处理驱动包 开始–><dependency> <groupId>net.coobird</groupId> <artifactId>thumbnailator</artifactId></dependency><!–图片处理驱动包 结束–>这里不再细说,想要有更多的了解,可以参考这篇博客:Thumbnailator框架的使用Excel操作我们在工作的过程中,经常会将数据导出到Excel表,或将Excel表的数据导入数据库。我们以前使用poi框架,但是,超过一定量的时候,会占用大量的内存,从而降低导入的效率。阿里巴巴现在开放出操作Excel表的easyexcel框架,对百万级的导入影响不是很大。以下是maven配置两个驱动依赖:<!–阿里巴巴的easyexcel驱动包 –><dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>{latestVersion}</version></dependency><!–poi驱动包 –><dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>${poi.version}</version></dependency><dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>${poi-ooxml.version}</version></dependency>这两个就不再细说,如果想要对easyexcel更深的了解,可以参考这篇博客:alibaba/easyexcel 框架使用。如果想要对poi有更深的了解,可以参考这篇博客:Apache POI使用详解guava包我们在开发的过程中,有时会用到guava驱动包。它是为了方便编码,并减少编码错误,用于提供集合,缓存,支持原语句,并发性,常见注解,字符串处理,I/O和验证的实用方法。使用它有以下好处:标准化 - Guava库是由谷歌托管。高效 - 可靠,快速和有效的扩展JAVA标准库优化 -Guava库经过高度的优化。同时,又有增加Java功能和处理能力的函数式编程,提供了需要在应用程序中开发的许多实用程序类的,提供了标准的故障安全验证机制,强调了最佳的做法等等。它的宗旨就是:提高代码质量、简化工作,促使代码更有弹性、更加简洁的工具。我们在项目中的配置包为:<!–guava驱动包 开始–> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId></dependency><!–guava驱动包 结束–>如果想要对其有更深的了解,可以参考这篇教程:guava入门教程freemarker包我们在开发的过程中,也许会用到这个框架。为什么要用到这个框架呢?我们有时需要动态地将xml文件转为doc文件,这个时候,就用到了freemarker包,如图所示:截图不是很全面,你会看到画红框的部分,这是一种占位符的标记,就相当于java中的形参一样。 当用户点击前端的下载按钮时,有些数据是无法直接转换成doc的,因为我们先把数据写进xml中,再将xml转化为doc。具体如何转换的可以参考该博客:Java将xml模板动态填充数据转换为word文档我们可以引用这个包: <!–freemarker驱动包 开始–><dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>${freemarker.version}</version></dependency><!–freemarker驱动包 结束–>由于篇幅限制,想要详细了解,可以参考这篇手册: freemarker在线手册servlet驱动包我记得当时在学java-web开发时,最开始用的就是servlet。接收客户端的输入,并经过一系列DB操作,将数据返回给客户端。但使用纯servlet不利于可视化界面。后来,使用了JSP开发,其是可视化界面。但是,当我们启动Tomcat后,JSP通过JSP引擎还是会转为servlet。从本质上来说,JSP和servlet是服务端语言。我最初用servlet和JSP开发的源码地址:图书馆项目后来,工作了以后。后端就用了springMVC,hibernate框架等,前端使用的是HTML、jQuery等。慢慢地脱离了JSP和servlet。但是,并没与完全与servlet分隔开,我们还时不时会用到servlet的一些类,比如HttpServletRequest,HttpServletResponse等类。既然使用了spring MVC框架,为什么还要用servlet的东西,比如,我们在导入和导出时,一个是接收前端导入的请求,一个是响应前端导出的请求。响应前端导出的代码,这里就用到了响应private static void downloadExcel(HttpServletResponse response, File newFile, String fileName) throws IOException { InputStream fis = new BufferedInputStream(new FileInputStream( newFile)); String substring = fileName.substring(fileName.indexOf(”/”) + 1); byte[] buffer = new byte[fis.available()]; fis.read(buffer); fis.close(); response.reset(); response.setContentType(“text/html;charset=UTF-8”); OutputStream toClient = new BufferedOutputStream( response.getOutputStream()); response.setContentType(“application/x-msdownload”); String newName = URLEncoder.encode( substring + System.currentTimeMillis() + “.xlsx”, “UTF-8”); response.addHeader(“Content-Disposition”, “attachment;filename="” + newName + “"”); response.addHeader(“Content-Length”, "” + newFile.length()); toClient.write(buffer); toClient.flush();}接收前端导入的请求 public static LinkedHashMap<String, List<JSONObject>> importMultiSheetExcel(HttpServletRequest request, LinkedHashMap<Integer, Integer> sheetDataStartRowMap, LinkedHashMap<Integer, String> sheetDataEndColMap) { LinkedHashMap<String, List<JSONObject>> resMap = new LinkedHashMap<>(); try { MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; ifNullThrow(multipartRequest, ResultCodeEnum.ILLEGAL_PARAM); MultipartFile file = multipartRequest.getFile(“file”); Workbook work = getWorkbook(file.getInputStream(), file.getOriginalFilename()); ifNullThrow(work, ResultCodeEnum.ILLEGAL_PARAM); 。。。}虽然我们现在使用了spring MVC,还是用到了servlet,而且shiro里面要使用到,以下是代码的配置:<!–servlet 开始–><!–shiro里面要使用到–><dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servlet.version}</version></dependency><!–servlet 结束–><dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version></dependency><!–servlet 结束–>如果想要了解servlet的话,可以参考该文档:Java Servlet API中文说明文档Lucene全文检索有时,我们在开发的过程中,需要做全文检索数据,就比如,我在Word文档中,全文检索某个词、某句话等,如图所示:这就是web端的全文检索。但是我做Java,当然,也需要全文检索。因而,我们就想到了Lucene。它是一套用于全文检索和搜寻的开源程式库,由Apache软件基金会支持和提供。提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻。在Java开发环境里,它是一个成熟的免费开源工具。就其本身而言,它是当前以及最近几年最受欢迎的免费Java信息检索程序库。我们在java的maven库中的配置为: <!– lucene 开始 –><dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>${lucene.version}</version></dependency><dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-highlighter</artifactId> <version>${lucene.version}</version></dependency><dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-analyzers-common</artifactId> <version>${lucene.version}</version></dependency><!– lucene 结束 –>想要对其有更深的了解,可以参考这篇笔记:Lucene学习笔记Quartz任务调度我们在开发的过程中,总想着要在某个时间,执行什么样的事情,于是呢,我们就相当了任务调度,比如:每天八点按时起床每年农历什么的生日每个星期都要爬一次山我们就可以用到Quartz这个框架,我们需要做一些配置,如图所示:我们可以在maven中的配置为:<!– quartz驱动包 开始–><dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>${quartz.version}</version></dependency><!– quartz驱动包 结束–>想要对其有根深多的了解,可参考这篇博客:Quartz使用总结zxing二维码我们经常使用到二维码,比如,添加微信好友的二维码,支付二维码、扫一扫二维码等等,那么,这是怎么实现的呢,其实,这有一个工具包,就是zxing工具包。它是谷歌旗下的工具类,我们可以用它来生成我们想要的二维码,但是,我们先要在maven项目中配置它。如代码所示:<!– 二维码驱动包 开始–><dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>${zxing.version}</version></dependency><dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>${zxing.se.version}</version></dependency><!– 二维码驱动包 开始–>想要对其有根深的了解,可以参考这篇博客:zxing实现二维码生成和解析WSDL包这个我也不大懂,也没有操作过,如果想要了解的话,可以参考这篇文档:WebService中的WSDL详细解析我们在maven中的怕配置为:<!– WSDL驱动包 开始–> <dependency> <groupId>wsdl4j</groupId> <artifactId>wsdl4j</artifactId> <version>${wsdl4j.version}</version></dependency><!– WSDL驱动包 结束–>配置文件配置文件来源于框架中的以下文件,如图所示:所有的配置文件都来源于资源包。这里就不再细说。总结要想成为架构师,首先学习别人的东西,他山之石,可以攻玉。 ...

March 30, 2019 · 5 min · jiezi

Idea基于Maven配置多JDK版本

Idea基于Maven配置多JDK版本1. 配置settings.xml2. 配置pom.xml3. 配置project structure3.1 配置SDK3.2 检查Modules相应SDK配置4. 配置Maven插件4.1 Maven基本配置4.2 配置Maven运行的JDK5. 配置编译JDK6. 编译打包6.1 使用Maven插件6.2 使用命令Idea基于Maven配置多JDK版本如果在本地开发环境中安装了多个JDK版本的话,需要在idea中自由切换,就需要利用Maven进行配置,配置后就可以非常方便的进行版本切换。配置步骤如下:1. 配置settings.xml在Maven的本地配置中,添加以下配置,配置JAVA_HOME和JAVA_VERSION两个属性。<profiles> <profile> <id>java6-compiler</id> <properties> <JAVA_HOME>C:\SoftCommon\Java\jdk1.6.0_45</JAVA_HOME> <JAVA_VERSION>1.6</JAVA_VERSION> </properties> </profile> <profile> <id>java7-compiler</id> <properties> <JAVA_HOME>C:\SoftCommon\Java\jdk1.7.0_67</JAVA_HOME> <JAVA_VERSION>1.7</JAVA_VERSION> </properties> </profile> <profile> <id>java8-compiler</id> <properties> <JAVA_HOME>C:\SoftCommon\Java\jdk1.8.0_202</JAVA_HOME> <JAVA_VERSION>1.8</JAVA_VERSION> </properties> <!– activeByDefault=true代表如果不指定某个固定id的profile,那么就使用这个环境 –> <activation> <activeByDefault>true</activeByDefault> </activation> </profile> <profile> <id>java9-compiler</id> <properties> <JAVA_HOME>C:\SoftCommon\Java\jdk-9</JAVA_HOME> <JAVA_VERSION>1.9</JAVA_VERSION> </properties> </profile> <profile> <id>java11-compiler</id> <properties> <JAVA_HOME>C:\SoftCommon\Java\jdk-11.0.2</JAVA_HOME> <JAVA_VERSION>11</JAVA_VERSION> </properties> </profile></profiles>2. 配置pom.xml在相应的项目工程中配置pom.xml中配置如下,主要是添加一个build标签,添加maven-compiler-plugin编译插件。<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.home>${JAVA_HOME}</java.home> <java.version>${JAVA_VERSION}</java.version> <maven.compiler.source>${JAVA_VERSION}</maven.compiler.source> <maven.compiler.target>${JAVA_VERSION}</maven.compiler.target></properties><build> <!–pluginmanagement标签一般用在父pom中,子元素可以包含plugins插件–> <pluginManagement> <plugins> <!– 一个好习惯,就是在此配置JDK的版本,这样就可以方便代码迁移 By Landy 2019.01.04–> <!–一般而言,target与source是保持一致的。但是,有时候为了让程序能在其他版本的jdk中运行(对于低版本目标jdk,源代码中需要没有使用低版本jdk中不支持的语法),会存在target不同于source的情况 。–> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>${maven.compiler.source}</source> <!– 源代码使用的开发版本 –> <target>${maven.compiler.target}</target> <!– 需要生成的目标class文件的编译版本 –> <!– 这下面的是可选项 –> <meminitial>128m</meminitial> <maxmem>512m</maxmem> <fork>true</fork> <!– fork is enable,用于明确表示编译版本配置的可用 –> <compilerVersion>${java.version}</compilerVersion> <!– 这个选项用来传递编译器自身不包含但是却支持的参数选项 –> <!–<compilerArgument>-verbose -bootclasspath ${java.home}\lib\rt.jar</compilerArgument>–> <executable>${java.home}/bin/javac</executable> </configuration> </plugin> </plugins> </pluginManagement></build>注意:pluginmanagement主要是用于父工程(module),然后在相应的子工程(module)中添加如下配置即可加入maven-compiler-plugin插件,这样就可以让子工程决定是否加载相应的Maven插件。<build> <!–然后,在子pom文件中就可以这样使用,省去了版本、配置等信息,只需指定groupId和artifactId即可。–> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> </plugin> </plugins></build>以上配置详情可以参看本例项目配置。配置完成刷新一下Maven插件(reimport),即可展示上面所配置的profile列表。如下所示:3. 配置project structure3.1 配置SDK打开idea中的project structure,配置相应的project sdk和project language level,配置如下(本案例采用JDK11),3.2 检查Modules相应SDK配置在Modules中有可能会没能自动刷新相应的sdk language level配置,这时候就需要手动设置。注意:经过本人现场测试,发现idea 2018.03版本的情况,他只能自动刷新的language level是JDK1.8+的版本。操作方法:点击Maven插件中的reimport,如下所示,4. 配置Maven插件4.1 Maven基本配置在Idea中需要配置一下Maven settings.xml文件和Maven本地仓库的位置,如果有本地安装的Maven也可以进行配置(没有则使用idea默认自带的Maven)。file –> settings –> maven 如下所示:4.2 配置Maven运行的JDK为了每次切换了Project JDK后,不需要再次进行设置可以选择Project JDK选项。如下所示,5. 配置编译JDK这时候,一般情况下,经过上面步骤,基本上就就可以进行相应的maven编译打包的操作了,但是有时候会遇到如下的问题,Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project xxxx Fatal error compiling: 无效的标记: -parameters -> [Help 1]这个错误是由于你项目所需jdk版本和你当前使用的jdk版本不一致导致的,因为我项目的pom.xml中定义了java版本为11,但是我实际idea中run这个项目却是1.8.要是你在intellij idea里面的maven窗口点击的打包编译的话,就在intellij idea设置项目jdk版本,直接Ctrl+Alt+s进入设置界面。6. 编译打包通过以上步骤就可以利用maven进行编译打包的操作了。6.1 使用Maven插件如果使用idea,则可以直接使用maven插件进行打包操作。如下图所示,6.2 使用命令如果使用Maven命令,如下所示,mvn -s D:\mvn_repository\settings.xml clean package -P java11-compilerjava11-compiler即为上面配置的jdk版本的profile id,并且需要制定相应的settings文件即可。关于本人笔者Github链接: https://github.com/landy8530 ...

March 30, 2019 · 1 min · jiezi

Jenkins+git+maven自动打包

linux环境配置1 安装Javayum install java-1.8.0-openjdk.x86_642 安装mavenyum install maven3 安装gityum install git4 安装tomcat下载最新的tomcat包,放到/root目录下,运行tar zxvf tomcat-*.tgz5 安装运行Jenkins点击这里下载Jenkins最新的war包,并放到/root/apache-tomcat-7.0.86/webapps/目录下。6 运行命令 cd apache-tomcat-7.0.86/webapps/ 进入war包所在目录,运行命令nohup java -jar jenkins.war –httpPort=8080 & 启动Jenkins。8080为默认端口,如果和其他服务冲突可改变为其他端口7 浏览器访问 服务器地址:端口号(例如192.168.0.100:8080)即可访问JenkinsJenkins配置1 安装必需的插件Deploy to container Plugin; GitLab Plugin;Maven Integration2 配置jenkins工具环境配置jdk配置Git配置Maven3 新建任务,选择构建maven项目4 source Code Management选择Git需要先点击add添加一个账号,打开这个页面填写你在gitlab的账号密码即可选择刚添加的账号,下面的分支记得改成自己需要的5 勾选一下构建快照6 Build这个pom文件不用修改,下面的语句可添加也可不添加7 配置到这一步已经可以自动打包了,我们构建看一下第一次运行会下载很多jar包,等待下载完成即可,打包成功后如下图所示报错1 [ERROR] Failed to execute goal on project : Could not resolve dependencies for project 🫙1.0-SNAPSHOT: The following artifacts could not be resolved: com.alibaba:dubbo🫙2.8.4, com.cloopen:sms-rest-sdk🫙2.6.3, com.taobao.pamirs.schedule:tbschedule🫙3.3.3.2: Could not find artifact com.alibaba:dubbo🫙2.8.4 in central (http://jcenter.bintray.com)缺少对应的jar包,可以直接从其他测试环境下复制过来 ...

March 27, 2019 · 1 min · jiezi

Apache Maven 的介绍和安装

Maven 简介什么是 MavenApache Maven,是一个软件项目管理及自动构建工具,由Apache软件基金会所提供,一个开源项目,由 Java 开发,并且只是用来管理 Java 项目的。Maven 的好处节省空间: Maven 项目的体积相比传统项目小很多,因为 Maven 将 Jar 包和项目分开了, 通过依赖管理来管理Jar包。一键构建项目: Maven 可以完成的工作:编译、测试、运行、打包、部署。 Maven 自带 Tomcat 插件,能直接用 mvn tomcat:run 命令部署运行项目,同时将项目代码编译。提高大型项目的开发效率Maven 的安装配置下载地址Apache 官网:https://maven.apache.org/down…Apache 官方镜像地址:https://mirrors.tuna.tsinghua…安装配置解压配置环境变量: 在 Path 里添加 Maven 目录里的 bin 文件夹的完整路径。Maven 仓库三种仓库本地仓库 (自己维护)本地仓库的配置只需要修改settings.xml文件就可以远程仓库(私服) (公司维护)中央仓库 (Maven 团队维护)三种仓库的关系Maven 的目录结构Maven 的命令常用命令需要进到项目目录中执行clean 清理编译好的文件compile 只编译主目录的文件test 只编译并运行 test 的目录的文件package 打包并放到 target 文件夹中install 把项目发布到本地仓库命令的生命周期(命令的执行顺序)clean 生命周期cleandefault 生命周期 compile test package installsite 生命周期 site 生成站点的说明文档命令和生命周期的阶段的关系不同的生命周期的命令可以同时执行。例如:mvn clean package

March 18, 2019 · 1 min · jiezi

Maven多模块之父子关系

Maven多模块项目,适用于一些比较大的项目,通过合理的模块拆分,实现代码的复用,便于维护和管理。尤其是一些开源框架,也是采用多模块的方式,提供插件集成,用户可以根据需要配置指定的模块。Maven多模块(pom)1.1 父模块创建先创建个简单的空的Maven Project作为父项目1.2 子模块创建重新创建一个Maven Project作为子项目1.3 父子模块(继承关系)注意:此时父子模块为两个独立的项目。步骤1:子项目中加入<parent>节点,传入父项目完整坐标。步骤2:将子项目中的依赖都注释掉。注意:此时子项目中的没有了Maven Dependencies。步骤3:将子项目注释的依赖添加到父项目中。注意:此时子项目中的依赖又添加回来了。这种直接在父工程中加入<dependencies>的方式,让子工程可以直接复用依赖,但是缺点是所有的子项目无条件继承父工程所有依赖,所以如果要在父工程中添加依赖只能针对非常通用的依赖。在父项目中再添加一个依赖。子项目同时也继承了新添加的依赖。那如果不想无条件继承父工程的所有依赖,而想让子项目自行选择需要的依赖又该如何做呢?1.4 dependencyManagement在父项目中用<dependencies>节点包裹<dependencies>节点,并且添加的是完整的依赖坐标(gav)。此时子项目中的Maven Dependencies又会消失,说明添加<dependencies>节点后,它并不负责相关依赖的下载。子项目加入相应同样依赖,注意不要加version(version继承自父项目),需要什么样的依赖就声明什么。特别注意,如果父项目提供了groupid和version,则删除子项目坐标中的groupid和version,直接继承父项目相关坐标。dependencyManagement的作用:依赖版本管理器本身并不下载任何依赖,只是管理依赖的版本。依赖的下载依然需要单独的<dependencies>(不加dependencyManagement,额外写一个)去做如果<dependencies>中的<dependency>没有声明版本号(version),maven会去寻找有无对应的dependencyManagement,当前工程没有就会向上找父工程。如果找到就以dependencyManagement中对应依赖声明的version为准,否则报错version is missing。

March 16, 2019 · 1 min · jiezi

SpringBoot使用SOFA-Lookout监控

本文介绍SpringBoot使用蚂蚁金服SOFA-Lookout配合Prometheus进行监控。1.SOFA-Lookout介绍上一篇已经介绍使用Prometheus进行暴露SpringBoot的一些指标进行监控,传送门,这一篇介绍如何使用SOFA-Lookout配合Prometheus。SOFA-Lookout是蚂蚁金服开源的一款解决系统的度量和监控问题的轻量级中间件服务。它提供的服务包括:Metrics 的埋点、收集、加工、存储与查询等。正如介绍的,SOFA-Lookout提供了一些常用的监控指标,比如JVM线程,JVM类加载,JVM内存,JVM垃圾回收,机器文件系统信息和机器信息。在1.5.0版本之后默认也提供了一些Linux操作系统的信息。具体可以查看:https://www.sofastack.tech/sofa-lookout/docs/client-ext-metrics2.SpringBoot使用SOFA-Lookout2.1 配置依赖新建项目,在项目中加入SOFA依赖,完整pom如下所示。<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!– lookup parent from repository –> </parent> <groupId>com.dalaoyang</groupId> <artifactId>springboot2_sofa_lookout</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot2_sofa_lookout</name> <description>springboot2_sofa_lookout</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.alipay.sofa.lookout</groupId> <artifactId>lookout-sofa-boot-starter</artifactId> <version>1.5.2</version> </dependency> <dependency> <groupId>com.alipay.sofa.lookout</groupId> <artifactId>lookout-reg-prometheus</artifactId> <version>1.5.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>2.2 配置SOFA-Lookout端口这里需要配置一个SOFA-Lookout的端口,生产环境使用的话一定要查看这个端口是不是被占用了。配置如下,这里配置的端口是8081。spring.application.name=springboot2_sofa_lookoutcom.alipay.sofa.lookout.prometheus-exporter-server-port=8081其实到这里,SpringBoot项目已经配置完成了,当然还可以自定义一些指标,这里不做介绍。3.Prometheus配置Prometheus需要配置一下刚刚SOFA-Lookout的端口,如下: - job_name: ‘springboot2_sofa_lookout’ scrape_interval: 5s static_configs: - targets: [’localhost:8081’]4.Grafana这里也可以将Prometheus展示给Grafana,我也查询了很多,但是貌似目前Grafana还没有默认推荐的Dashboard,大家可以根据情况自行构建,当然,如果有好的也希望可以推荐一下。5.测试启动SpringBoot应用,控制台如下所示。看到红框部分就是启动成功了。接下来查看Prometheus界面,如下。这里Grafana在看一下Grafana界面,如图。6.源码源码地址:https://gitee.com/dalaoyang/springboot_learn/tree/master/springboot2_sofa_lookout本文作者:dalaoyang阅读原文本文为云栖社区原创内容,未经允许不得转载。

March 12, 2019 · 1 min · jiezi

Maven 教程

介绍构建(build)一个项目包括:下载依赖,编译源代码,执行单元测试,以及打包编译后的源代码等一系列子任务。手工的执行这些任务是一项非常繁琐,且容易出错的事情。Maven封装了这些子任务,并提供给用户执行这些子任务的命令。简而言之,Maven是Java项目的一个管理和构建(build)工具。2. 项目对象模型(Project Object Model)项目对象模型(以下简称POM)是Maven的基本组成单元,它是位于项目主目录下的一个xml文件(pom.xml),Maven使用pom.xml文件中的信息来构建(build)项目。一个简单的pom.xml的结构看起来如下:<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 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany.app</groupId> <artifactId>my-app</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>my-app</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <properties> <maven.compiler.source>1.6</maven.compiler.source> <maven.compiler.target>1.6</maven.compiler.target> </properties> <build> <plugins> <plugin> //… </plugin> </plugins> </build></project>本小结将介绍pom.xml中常用的一些元素。2.1 项目标识符(Project Identifiers)groupId - 创建项目的公司或者组织的名称artifactId - 项目的名称version - 项目的版本号packaging - 项目的打包方式(jar/war/pom)GAV (groupId:artifactId:version)是Maven项目的唯一表示符。packaging决定Maven生成包的类型,默认值是jar。2.2 依赖(dependencies)pom.xml文件通过元素<dependency>来声明外部依赖,例如:<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency></dependencies>声明项目依赖3.8.1版本的junit。默认情况下,Maven将在构建项目的时候从Maven的中央仓库(Central Repository)下载依赖到本地仓库(${USER_HOME/.m2/repository/})。不过用户也可以通过元素<repository>来声明备选仓库(alternate repository)。2.3 属性(Properties)可以像在Java等编程语言中定义变量一样,在pom.xml文件中定义属性,这样就可以达到一处定义,多处使用的目的,使用和维护起来也更加容易。pom.xml中通过元素<properties>定义属性,通过占位符${property_name}使用属性。如下:<properties> <spring.version>4.3.5.RELEASE</spring.version></properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency></dependencies>如果在将来需要升级spring-core和spring-context的版本,那时将只需要修改属性spring.version的值。2.4 构建(build)未完待续……参考https://www.baeldung.com/mavenhttps://maven.apache.org/guid…https://maven.apache.org/guid…

March 10, 2019 · 1 min · jiezi

SpringBoot使用prometheus监控

本文介绍SpringBoot如何使用Prometheus配合Grafana监控。1.关于PrometheusPrometheus是一个根据应用的metrics来进行监控的开源工具。相信很多工程都在使用它来进行监控,有关详细介绍可以查看官网:https://prometheus.io/docs/in…。2.有关GrafanaGrafana是一个开源监控利器,如图所示。从图中就可以看出来,使用Grafana监控很高大上,提供了很多可视化的图标。官网地址:https://grafana.com/3.SpringBoot使用Prometheus3.1 依赖内容在SpringBoot中使用Prometheus其实很简单,不需要配置太多的东西,在pom文件中加入依赖,完整内容如下所示。<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!– lookup parent from repository –></parent><groupId>com.dalaoyang</groupId><artifactId>springboot2_prometheus</artifactId><version>0.0.1-SNAPSHOT</version><name>springboot2_prometheus</name><description>springboot2_prometheus</description><properties> <java.version>1.8</java.version></properties><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> <version>1.1.3</version> </dependency></dependencies><build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins></build></project>3.2 配置文件配置文件中加入配置,这里就只进行一些简单配置,management.metrics.tags.application属性是本文配合Grafana的Dashboard设置的,如下所示:spring.application.name=springboot_prometheusmanagement.endpoints.web.exposure.include=*management.metrics.tags.application=${spring.application.name}3.3 设置application修改启动类,如下所示.@SpringBootApplicationpublic class Springboot2PrometheusApplication {public static void main(String[] args) { SpringApplication.run(Springboot2PrometheusApplication.class, args);}@BeanMeterRegistryCustomizer<MeterRegistry> configurer( @Value("${spring.application.name}”) String applicationName) { return (registry) -> registry.config().commonTags(“application”, applicationName);}}SpringBoot项目到这里就配置完成了,启动项目,访问http://localhost:8080/actuator/prometheus,如图所示,可以看到一些度量指标。4.Prometheus配置4.1 配置应用在prometheus配置监控我们的SpringBoot应用,完整配置如下所示。my global configglobal: scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. # scrape_timeout is set to the global default (10s).Alertmanager configurationalerting: alertmanagers:static_configs:targets: # - alertmanager:9093Load rules once and periodically evaluate them according to the global ’evaluation_interval’.rule_files: # - “first_rules.yml” # - “second_rules.yml"A scrape configuration containing exactly one endpoint to scrape:Here it’s Prometheus itself.scrape_configs:job_name: ‘prometheus’ static_configs:targets: [‘127.0.0.1:9090’]以下内容为SpringBoot应用配置job_name: ‘springboot_prometheus’ scrape_interval: 5s metrics_path: ‘/actuator/prometheus’ static_configs:- targets: [‘127.0.0.1:8080’]4.2 启动Prometheus启动Prometheus,浏览器访问,查看Prometheus页面,如图所示。点击如图所示位置,可以查看Prometheus监控的应用。列表中UP的页面为存活的实例,如图所示。也可以查看很多指数,如下所示。5.Grafana配置启动Grafana,配置Prometheus数据源,这里以ID是4701的Doshboard为例(地址:https://grafana.com/dashboard…)如图。在Grafana内点击如图所示import按钮在如图所示位置填写4701,然后点击load。接下来导入Doshboard。导入后就可以看到我们的SpringBoot项目对应的指标图表了,如图。6.源码源码地址:https://gitee.com/dalaoyang/s…本文作者:dalaoyang阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

March 8, 2019 · 1 min · jiezi

maven

Maven mvn -Dmaven.test.skip=true -U clean installmvn clean package -U (强制拉一次)mvn archetype:create-from-project mvn archetype:generate -DarchetypeCatalog=localmvn dependency:tree mvn clean package -Dmaven.test.skip=true -Ptest 认识Maven优势约定优于配置简单测试支持构建简单CI插件丰富下载 https://maven.apache.org/down…安装 maven-model-builder-3.6.0.jar/org/apache/maven/model文件分析自己的classloader所有自己的仓库配置超级父pom配置 MVM_HOMEWindows pathLinux .bash_profileexport M2_HOME=/Users/xx/tools/apache/apache-maven-3.6.0MAVEN_OPTS 配置setting.xml<mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf></mirror><mirror><id>ui</id><mirrorOf>central</mirrorOf><name>Human Readable Name for this Mirror.</name><url>http://uk.maven.org/maven2/</url></mirror><mirror><id>osc</id><mirrorOf>central</mirrorOf><url>http://maven.oschina.net/content/groups/public/</url></mirror><mirror><id>osc_thirdparty</id><mirrorOf>thirdparty</mirrorOf><url>http://maven.oschina.net/content/repositories/thirdparty/</url></mirror>PomgroupId 一般是域名反写 com.zzjsonartfactId 功能命名version 版本号packaging 打包方式 默认是jardependencyManagement 只能出现在父pom 统一版本号 声明 (子POM里用到再引)Dependency Type 默认jarscopecompile 默认 编译(maven编译整个项目) 例如spring-coretest 测试provided 编译 例如 servlet,tomcat已经有了 打包不会打进去,相当于compile但是在打包阶段做了exclude操作runtime 运行时 例如JDBC驱动实现system 本地一些jar 例如短信jar依赖传递compile:编译依赖范围,在编译,测试,运行时都需要。test: 测试依赖范围,测试时需要。编译和运行不需要。如Junitruntime: 运行时依赖范围,测试和运行时需要。编译不需要。如JDBC驱动包provided:已提供依赖范围,编译和测试时需要。运行时不需要。如servlet-apisystem:系统依赖范围。本地依赖,不在maven中央仓库。第一列表示直接依赖的scope,第一行表示间接依赖的scope compiletestprovidedruntimecompilecompile–runtimetesttest–testprovidedprovided-providedprovidedruntimeruntime–runtime依赖仲裁mvn dependency:tree如果都定义了版本,那么以最近的为准 最短路径原则 加载先后原则exclusions 排除包生命周期clean 清理项目pre-clean执行一些清理前需要完成的工作clean清理上一次构建生成的文件post-clean执行一些清理后需要完成的工作defaultSite lifecycle/phase/goal 1.A Build Lifecycle is Made Up of Phases 一个生命周期由多个phase组成的 2.A Build Phase is Made Up of Plugin Goals 一个phases是由多个goals组成的生命周期运行会从前往后版本管理1.0-SNAPSHOT i. repository 删除 ii. mvn clean package -U (强制拉一次)主版本号.次版本号.增量版本号-<里程碑版本>1.0.0-RELAESE常用命令compileclean 删除target/test test case junit/testNGpackage 打包 <plugins> <plugin> <artifactId>plugin</artifactId> <groupId>com.zzjson</groupId> <version>1.1</version> <configuration> <msg> ddd </msg> <list> <list> d </list> <list> d1 </list> </list> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>myplugin</goal> </goals> </execution> </executions> </plugin> </plugins>install 把项目install到local repodeploy 发本地jar发布到remote插件常用插件https://maven.apache.org/plug…http://www.mojohaus.org/plugi...findbugs 静态代码检查versions 统一升级版本号<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>versions-maven-plugin</artifactId> <version>2.3</version></plugin>http://www.mojohaus.org/versions-maven-plugin/index.html mvn versions:set -DnewVersion=1.1-SNAPSHOTsource 打包源代码<plugin> <artifactId>maven-source-plugin</artifactId> <version>2.3</version> <executions> <execution> <id>attach-sources</id> <phase>install</phase> <goals> <goal>jar-no-fork</goal> </goals> </execution> </executions></plugin>assembly 打包zip、war<plugin> <artifactId>maven-assembly-plugin</artifactId> <version>3.1.0</version> <configuration> <archive> <manifest> <mainClass>shuncom.dubbo.task.main.BootStrap</mainClass> </manifest> </archive> <descriptorRefs>jar-with-dependencies</descriptorRefs> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions></plugin>tomcat7<plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <path>/</path> </configuration></plugin>自定义插件https://maven.apache.org/guides/plugin/guide-java-plugin-development.html<packaging>maven-plugin</packaging>导入依赖<dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-plugin-api</artifactId> <version>3.5.0</version> </dependency> <dependency> <groupId>org.apache.maven.plugin-tools</groupId> <artifactId>maven-plugin-annotations</artifactId> <version>3.5</version> </dependency>extends AbstractMojomvn install参数传递 Profile使用场景 dev/test/prosetting.xml 家和公司两套仓库下载 http://books.sonatype.com/nex…访问地址http://lohost:8081/nexus(自带jetty)admin/admin123内容配置Type: 依赖jar包的方式group 把group作为合集提供,挨个jar去仓库查找hosted 本地的 三方的 阿里短信jar包 released snapshostsproxy 当maven dependce本地仓库没有找到,私服也没有,则去下载,从远端下载到私服发布在pom.xml配置<distributionManagement> <repository> <id>repo-mirrors</id> <name>center-repository</name> <url>http://uk.maven.org/maven2</url> </repository> <snapshotRepository> <id>repo-mirrors</id> <name>center-repository</name> <url>http://uk.maven.org/maven2</url> </snapshotRepository></distributionManagement>mvn deploy登录 也需要验证用户名密码,id需要和pom中一致下载jar配置配置mirrorProfilearchetype 模版化生成一个archetypemvn archetype:create-from-project进入目录cd /target/generated-sources/archetypemvn installb) 从archetype创建项目 mvn archetype:generate -DarchetypeCatalog=localProfile配置文件<profiles> <profile> <id>dev</id> <properties> <profiles.active>dev</profiles.active> </properties> <activation> <activeByDefault>false</activeByDefault> </activation> </profile> <profile> <id>prod</id> <properties> <profiles.active>prod</profiles.active> </properties> <activation> <activeByDefault>true</activeByDefault> </activation> </profile> <profile> <id>test</id> <properties> <profiles.active>test</profiles.active> </properties> <activation> <activeByDefault>false</activeByDefault> </activation> </profile></profiles><resources> <resource> <directory>${basedir}/src/main/resources</directory> <excludes> <exclude>conf/**</exclude> </excludes> </resource> <resource> <directory>src/main/resources/conf/${profiles.active}</directory> </resource></resources>代码,指定不同的环境Setting.xml<profile> <id>ali</id> <repositories> <repository> <id>nexus</id> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <releases> <enabled>true</enabled> <updatePolicy>always</updatePolicy> <checksumPolicy>warn</checksumPolicy> </releases> <snapshots> <enabled>true</enabled> <updatePolicy>always</updatePolicy> <checksumPolicy>fail</checksumPolicy> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>nexus</id> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <releases> <enabled>true</enabled> <updatePolicy>always</updatePolicy> <checksumPolicy>warn</checksumPolicy> </releases> <snapshots> <enabled>true</enabled> <checksumPolicy>fail</checksumPolicy> <updatePolicy>always</updatePolicy> </snapshots> </pluginRepository> </pluginRepositories></profile><profile> <id>external</id> <repositories> <repository> <id>repo-mirrors</id> <url>http://uk.maven.org/maven2</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>plugin-repo-mirror</id> <url>http://uk.maven.org/maven2</url> </pluginRepository> </pluginRepositories></profile>mvn clean package -Dmaven.test.skip=true -Ptest 仓库[root@snails ~]# wget http://download.sonatype.com/nexus/3/latest-unix.tar.gzdependencyManagement使用能够帮助我们进行子项目的版本号管理<dependencyManagement> <dependencies> <dependency> <groupId>com.zzjson.dubbo.order</groupId> <artifactId>order-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies></dependencyManagement>版本SNAPSHOT 版本会替换仓库中的jarrelease 版本不会替换 ...

March 8, 2019 · 2 min · jiezi

Fundebug后端Java异常监控插件更新至0.3.1,修复Maven下载失败的问题

摘要: 0.3.1修复Maven下载失败的问题。监控Java应用1. pom.xml 配置fundebug-java依赖<dependency> <groupId>com.fundebug</groupId> <artifactId>fundebug-java</artifactId> <version>0.3.1</version></dependency>2. 在项目中引入 fundebug 并配置 apikeyimport com.fundebug.Fundebug;Fundebug fundebug = new Fundebug(“apikey”);注意:获取apikey需要免费注册帐号并且创建项目。可以参考 Demo 项目Fundebug/fundebug-java-demo。监控Spring应用1. pom.xml配置fundebug-spring依赖<dependency> <groupId>com.fundebug</groupId> <artifactId>fundebug-spring</artifactId> <version>0.3.1</version></dependency>2. 在项目中引入fundebug并配置apikey新增FundebugConfig.javaimport org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Import;import com.fundebug.Fundebug;import com.fundebug.SpringConfig;@Configuration@Import(SpringConfig.class)public class FundebugConfig { @Bean public Fundebug getBean() { return new Fundebug(“apikey”); }}注意:获取apikey需要免费注册帐号并且创建项目。可以参考Demo项目Fundebug/fundebug-spring-demo。参考Fundebug文档 - JavaMaven入门教程关于FundebugFundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了9亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用!版权声明转载时请注明作者Fundebug以及本文地址:https://blog.fundebug.com/2019/01/07/fundebug-java-0-2-0/

February 27, 2019 · 1 min · jiezi

在使用spring-boot-maven-plugin的下生成普通的jar包

当使用springboot的maven插件的时候,默认是生成的可执行jar包,如果我们想让其生成普通的jar包该怎么做呢?一、解决办法直接上方法mvn clean package -D spring-boot.repackage.skip=true 加上-Dspring-boot.repackage.skip=true参数即可,此时只会生成一个普通的jar包二、理解当使用SpringBoot开发项目的时候,会使用到spring-boot-maven-plugin插件官方文档:https://docs.spring.io/spring…Spring Boot Maven plugin有5个Goals:命令说明spring-boot:repackage默认goal。在mvn package之后,再次打包可执行的jar/war,<br/>并将mvn package生成的软件包重命名为*.originalspring-boot:run运行Spring Boot应用spring-boot:start在mvn integration-test阶段,进行Spring Boot应用生命周期的管理spring-boot:stop在mvn integration-test阶段,进行Spring Boot应用生命周期的管理spring-boot:build-info生成Actuator使用的构建信息文件build-info.properties当时用spring-boot-maven-plugin插件时,下面的mvn命令会生成两个文件:mvn package执行后会看到生成的两个jar文件:.jar.jar.original这是由于在执行上述命令的过程中,Maven首先在package阶段打包生成*.jar文件;然后执行spring-boot:repackage重新打包,将之前的*.jar包重命名为*.jar.original,然后生成springboot的可执行jar包文件*.jar所以,我们只需要跳过spring-boot:repackage阶段即可。

February 26, 2019 · 1 min · jiezi

gradle-学习笔记(2)-多项目构建

记得在maven中支持多个子项目的构建方法,同样的在gradle 中也会支持多项目的构建方法还记得在maven中如何配置多项目工程吗, 这里回忆一下首先我们需要一个父元素pom文件比如这样<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.kyssion</groupId> <artifactId>maven-demo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging></project>而在gradle中,我们并不需要指定父元素的标签,我们只需要编写好对应的文件夹名称,并且将文件夹名称和对应的目录结构对应清,gradle 就能自动的识别这个子项目比如我创建这样一个子项目名称是greeting-library子项目中的配置未见build.gradleplugins { id ‘groovy’}group ‘com.kyssion’version ‘1.0-SNAPSHOT’repositories { mavenCentral()}dependencies { compile ‘org.codehaus.groovy:groovy-all:2.5.6’ testCompile group: ‘junit’, name: ‘junit’, version: ‘4.12’}父项目中的setting.gradle中添加这样一条配置include ‘greeting-library’这样就能使用greeting-library目录下的gradle子项目了一个简单的项目这使用一个简单的项目介绍一下这个如何使用gradle 实现整合打包项目结构和模块划分├── build.gradle├── greeter│ ├── build│ │ ├── classes│ │ │ └── java│ │ │ └── main│ │ │ └── greeter│ │ │ └── Greeter.class│ │ ├── distributions│ │ │ ├── greeter-1.0-SNAPSHOT.tar│ │ │ └── greeter-1.0-SNAPSHOT.zip│ │ ├── generated│ │ │ └── sources│ │ │ └── annotationProcessor│ │ │ └── java│ │ │ └── main│ │ ├── libs│ │ │ └── greeter-1.0-SNAPSHOT.jar│ │ ├── scripts│ │ │ ├── greeter│ │ │ └── greeter.bat│ │ └── tmp│ │ ├── compileJava│ │ └── jar│ │ └── MANIFEST.MF│ ├── build.gradle│ └── src│ ├── main│ │ ├── java│ │ │ └── greeter│ │ │ └── Greeter.java│ │ └── resources│ └── test│ ├── java│ └── resources├── greeting-library│ ├── build│ │ ├── classes│ │ │ └── groovy│ │ │ ├── main│ │ │ │ └── greeter│ │ │ │ └── GreetingFormatter.class│ │ │ └── test│ │ │ └── greeter│ │ │ └── GreetingFormatterSpec.class│ │ ├── generated│ │ │ └── sources│ │ │ └── annotationProcessor│ │ │ └── groovy│ │ │ ├── main│ │ │ └── test│ │ ├── libs│ │ │ └── greeting-library-1.0-SNAPSHOT.jar│ │ ├── reports│ │ │ └── tests│ │ │ └── test│ │ │ ├── classes│ │ │ │ └── greeter.GreetingFormatterSpec.html│ │ │ ├── css│ │ │ │ ├── base-style.css│ │ │ │ └── style.css│ │ │ ├── index.html│ │ │ ├── js│ │ │ │ └── report.js│ │ │ └── packages│ │ │ └── greeter.html│ │ ├── test-results│ │ │ └── test│ │ │ ├── binary│ │ │ │ ├── output.bin│ │ │ │ ├── output.bin.idx│ │ │ │ └── results.bin│ │ │ └── TEST-greeter.GreetingFormatterSpec.xml│ │ └── tmp│ │ ├── compileGroovy│ │ │ └── groovy-java-stubs│ │ ├── compileTestGroovy│ │ │ └── groovy-java-stubs│ │ ├── jar│ │ │ └── MANIFEST.MF│ │ └── test│ │ └── jar_extract_15307722744227685163_tmp│ ├── build.gradle│ └── src│ ├── main│ │ ├── groovy│ │ │ └── greeter│ │ │ └── GreetingFormatter.groovy│ │ ├── java│ │ └── resources│ └── test│ ├── groovy│ │ └── greeter│ │ └── GreetingFormatterSpec.groovy│ ├── java│ └── resources└── settings.gradle这个项目中划分为根项目gradle-demo,包项目greeting-library,core可运行项目greeter。注意: 通过上面的例子我们可以得出,在gradle 中不同的子项目的命名规则是使用文件夹的注意:在java 项目中,gradle 要求 必须指定项目的main函数具体方法见下方这里针对gradle的多语言的编程的目录结构做一下补充,gradle中源代码同意放置在这样的位置中src->main/test->编程语言名称文件夹 下plugins { id ‘java’ id ‘application’}group ‘com.kyssion’version ‘1.0-SNAPSHOT’sourceCompatibility = 1.8mainClassName = “greeter.Greeter” //这一句指定了main函数repositories { mavenCentral()}dependencies { compile project(’:greeting-library’) testCompile group: ‘junit’, name: ‘junit’, version: ‘4.12’}总结在构建gradle 多模块项目的时候,一定要注意多模块的之间的引用,模块中main函数的编写,父模块的include ...

February 26, 2019 · 2 min · jiezi

Maven 国内源配置(2019/2/14)

新年开工后要开始新的项目,但是发现一些项目的依赖没有在阿里仓库Central或Public源之中,项目依赖还是要在外网中下载,很慢、很烦······所以一番查找后,替换为阿里官方仓库服务站点:https://maven.aliyun.com/mvn/…具体操作打开 ${maven_home}/conf/settings.xml 在<mirrors>上面配置<mirror> <id>aliyun-public</id> <mirrorOf></mirrorOf> <name>aliyun public</name> <url>https://maven.aliyun.com/repository/public</url></mirror><mirror> <id>aliyun-central</id> <mirrorOf></mirrorOf> <name>aliyun central</name> <url>https://maven.aliyun.com/repository/central</url></mirror><mirror> <id>aliyun-spring</id> <mirrorOf></mirrorOf> <name>aliyun spring</name> <url>https://maven.aliyun.com/repository/spring</url></mirror><mirror> <id>aliyun-spring-plugin</id> <mirrorOf></mirrorOf> <name>aliyun spring-plugin</name> <url>https://maven.aliyun.com/repository/spring-plugin</url></mirror><mirror> <id>aliyun-apache-snapshots</id> <mirrorOf></mirrorOf> <name>aliyun apache-snapshots</name> <url>https://maven.aliyun.com/repository/apache-snapshots</url></mirror><mirror> <id>aliyun-google</id> <mirrorOf></mirrorOf> <name>aliyun google</name> <url>https://maven.aliyun.com/repository/google</url></mirror><mirror> <id>aliyun-gradle-plugin</id> <mirrorOf></mirrorOf> <name>aliyun gradle-plugin</name> <url>https://maven.aliyun.com/repository/gradle-plugin</url></mirror><mirror> <id>aliyun-jcenter</id> <mirrorOf></mirrorOf> <name>aliyun jcenter</name> <url>https://maven.aliyun.com/repository/jcenter</url></mirror><mirror> <id>aliyun-releases</id> <mirrorOf></mirrorOf> <name>aliyun releases</name> <url>https://maven.aliyun.com/repository/releases</url></mirror><mirror> <id>aliyun-snapshots</id> <mirrorOf></mirrorOf> <name>aliyun snapshots</name> <url>https://maven.aliyun.com/repository/snapshots</url></mirror> <mirror> <id>aliyun-grails-core</id> <mirrorOf></mirrorOf> <name>aliyun grails-core</name> <url>https://maven.aliyun.com/repository/grails-core</url></mirror><mirror> <id>aliyun-mapr-public</id> <mirrorOf></mirrorOf> <name>aliyun mapr-public</name> <url>https://maven.aliyun.com/repository/mapr-public</url></mirror>

February 14, 2019 · 1 min · jiezi

maven项目在svn中的上传与检出

前言企业开发中经常使用svn来为我们控制代码版本,也经常使用maven来管理项目。下面将介绍一下如何将maven项目上传到svn中,如何将项目从svn中检出。上传到svnmaven项目上传与普通项目上传并无区别。这里做一下简单介绍:右击项目;选择Team;选择Share Project;仓库类型选择svn 点击next选择你要分享的资源库。点击next选择使用指定的模块名。然后在浏览中选择要上传的位置。然后点击finish。点击finish后进入同步视图界面。这个界面需要我们选择将哪些内容资源上传至svn。 我们将除了.classpath .project .setting .git 的文件选中然后右键选择提交(1.选中不需要提交的文件右键添加到忽略或者在window->preference->svn中设置忽略的文件)。检出检出maven项目与其他项目的区别在于检出后需要转换为maven项目在svn资源库中选中要导出的maven项目。然后右击选择 检出为。然后选择作为工作空间中的项目检出(注意不要选错)。点击finish。检出项目后,此时的项目并不是maven项目。需要转换为maven项目。选中项目然后右击 选择 configure 下的 convert to Maven Project。如果是聚合型maven项目我们上传时只上传总的聚合模块,当我们检出后可以先改项目删除,但记住删除时不要勾选delete project contents on disk.然后我们再导入maven项目即可。

February 14, 2019 · 1 min · jiezi

使用Gradle发布构件(Jar)到Maven中央仓库

OSSRH在开始之前,先对OSSRH做下了解是很必要的,因为一开始,我并不知道这是个啥玩儿意。我想和我一样的人应该还是有很多的。OSSRH:Sonatype Open Source Software Repository Hosting Service,为开源软件提供maven仓库托管服务。你可以在上面部署snapshot、release等,最后你可以申请把你的release同步到Maven Central Repository(Maven中央仓库)。个人的理解,OSSRH是Maven中央仓库的前置审批仓库,只有你完全符合了发布要求,成功的将你的项目发布到了OSSRH,才有机会申请同步到Maven中央仓库。这篇主要是记录这整个流程,方便以后自己查阅,同时可以帮助到想做同样事情的朋友。1、注册Sonatype JIRA账号JIRA是Atlassian公司出品的项目与事务跟踪工具,被广泛应用于缺陷跟踪、客户服务、需求收集、流程审批、任务跟踪、项目跟踪和敏捷管理等工作领域。网址:https://issues.sonatype.org/无非就是填写下注册信息,没有什么特别的2、创建一个Issue填写资料可以在头部看到一个Create的按钮会弹出Create Issue表单Project选择Community Support - Open Source Project Repository Hosting (OSSRH)Issue Type选择New ProjectSummary写个标题做个简单概述你要做啥。真不知道写什么,直接把项目名称写上就行,我就这么干了哈。Group Id自己有域名可以使用子域名作为Group Id 。例:我的项目叫paladin2,那么就用org.zhangxiao.paladin2作为Group Id注意:不能瞎编一个,因为后面审核人员会来审核你是否是该域名的拥有者自己没域名可以借助github,例:我的用户名为michaelzx,那么就用com.github.michaelzx.paladin2作为作为Group IdProject URL要与Group Id一定关联性例1:Project URL=http://paladin2.zhangxiao.orgGroup Id=org.zhangxiao.paladin2例2:Project URL=https://github.com/michaelzx/Paladin2Group Id=com.github.michaelzx.paladinSCM url版本仓库的拉取地址等待回复如果有问题,老外在评论中把问题给你指出来,可以在原有的issue把资料改正确我之前是犯了个低级的错误把Group Id写成了域名审核人员要处理的issue很多,你可能要耐心等待一会,不要急 我之前急了,就重新提交了2个新的issue,最后管理员还是耐心的把重复的issue关闭如果一切顺利,那么你会收到审核人员,这样的一个评论:3、准备工作文件要求为了确保中央存储库中可用组件的质量水平,OSSRH对提交的文件有明确的要求。一个基础的提交,应该包含一下文件:example-application-1.4.7.pomexample-application-1.4.7.pom.ascexample-application-1.4.7.jarexample-application-1.4.7.jar.ascexample-application-1.4.7-sources.jarexample-application-1.4.7-sources.jar.ascexample-application-1.4.7-javadoc.jarexample-application-1.4.7-javadoc.jar.asc除了jar包和pom文件,Javadoc和Sources是必须的,后面会说到用Gradle的一些插件来生成每个文件都有一个对应的asc文件,这是GPG签名文件,可以用于校验文件GPG安装说明:后续过程均在OSX环境下OSX下可以通过brew来安装gpg命令行工具$ brew update$ brew install -v gpg你会发现从brew的gpg命令行工具,做了国际化支持,连help都是中文,赞????另外推荐一个工具GPG Suite,传送门在OSX提供了一个图形化界面,把GPG作为钥匙串来做管理,蛮有意思,不过感觉缺失点功能Windows下可以安装gpg4win,网址:传送门 页面最上面有个很大的下载按钮,点了以后,貌似会让你捐个款啥的……不过你可以往下看,有所有版本的列表地址,可以跳过捐款,在祭上一个传送门人家只是隐藏的好了一些而已,还是免费的。装完了以后,在命令行中也可以用gpg了公钥、私钥、签名GPG的默认秘钥类型是RSA,这里涉及涉及几个概念公钥(public-key)、私钥(secret-key)、签名(sign/signature)公钥和私钥是成对公钥加密,私钥解密。私钥签名,公钥验证。新建一个密钥生成了密钥以后,才能导出公钥、私钥$ gpg –generate-key创建的时候,会让你输入密码,别输了以后忘记了,后面gradle插件中会用到。查看已经生成的密钥$ gpg -k———————————pub rsa2048 2019-01-25 [SC] [有效至:2021-01-24] 72963F6B33D962380B1DC4BD8C446B86DF855F85uid [ 绝对 ] zhangxiao’paladin2 <mail@zhangxiao.org>sub rsa2048 2019-01-25 [E] [有效至:2021-01-24]72963F6B33D962380B1DC4BD8C446B86DF855F85,这个叫做密钥指纹,用来做唯一识别 后面8位DF855F85,叫做标识或KEY ID,后面会用到导出私钥文件很多英文文档或文章中经常出现KeyRingFile这个词,这个到底是啥?https://users.ece.cmu.edu/ad…Keys are stored in encrypted form. PGP stores the keys in two files on your hard disk; one for public keys and one for private keys. These files are called keyrings. As you use PGP, you will typically add the public keys of your recipients to your public keyring. Your private keys are stored on your private keyring. If you lose your private keyring, you will be unable to decrypt any information encrypted to keys on that ring.$ gpg –export-secret-keys [密钥指纹] > secret.gpg以上命令就可以生成一个二进制的私钥文件,后面需要配置到gradle中,让插件帮我们给文件批量签名加上-a会生成一个用ASCII 字符封装的文本文件,方便复制,不过我们这里不需要上传公钥到公钥服务器$ gpg –keyserver keyserver.ubuntu.com –send-keys [密钥指纹]在sonatype的仓库提交后,会需要一个校验步骤 会需要从多个公钥服务器上下载匹配的公钥,然后来校验你上传的文件的签名简单的说,你用来签名的私钥和你上传的公钥,必须要一对,这样才能通过校验以下是sonatype会去拉取的公钥服务器列表keys.gnupg.netpool.sks-keyservers.netkeyserver.ubuntu.com为什么我要特意列出来?因为有些文章或教程里面,都仅给出了一个服务器,如pool.sks-keyservers.net但是,我在实际操作有时候因为网络原因,并不是总能成功上传。所以,如果把公钥上传到keyserver.ubuntu.com也是OK的。总结密钥的key id密钥的password私钥的KeyRingFile公钥上传到了公钥服务器准备好了以上几项,我们就可以开始撸Gradle了有些文章说,最好是先生成一个吊销凭证备用,暂时不知道什么场景下会用到4、配置Gradle插件Gradle版本:4.10.2start.spring.io中生成的gradle工程,是用4.10.2。所以我就这个版本为标准。signing:https://docs.gradle.org/4.10….maven-publish:https://docs.gradle.org/4.10….主要核心就是以上两个插件修改build.gradle// … 在最下面新增以下代码apply plugin: ‘maven-publish’apply plugin: ‘signing’task sourcesJar(type: Jar) { from sourceSets.main.allJava classifier = ‘sources’}task javadocJar(type: Jar) { from javadoc classifier = ‘javadoc’}publishing { // 定义发布什么 publications { mavenJava(MavenPublication) { // groupId = project.group // artifactId = project.name // version = project.version // groupId,artifactId,version,如果不定义,则会按照以上默认值执行 from components.java artifact sourcesJar artifact javadocJar pom { // 构件名称 // 区别于artifactId,可以理解为artifactName name = ‘Paladin2 Common’ // 构件描述 description = ‘Paladin2 Common library’ // 构件主页 url = ‘https://paladin2.zhangxiao.org’ // 许可证名称和地址 licenses { license { name = ‘The Apache License, Version 2.0’ url = ‘http://www.apache.org/licenses/LICENSE-2.0.txt' } } // 开发者信息 developers { developer { name = ‘听风.Michael’ email = ‘mail@zhangxiao.org’ } } // 版本控制仓库地址 scm { url = ‘https://github.com/michaelzx/Paladin2' connection = ‘scm:git:git://github.com/michaelzx/Paladin2.git’ developerConnection = ‘scm:git:ssh://git@github.com:michaelzx/Paladin2.git’ } } } } // 定义发布到哪里 repositories { maven { // 从命令行参数中获取账号密码,这样你把这个文件传到GitHub这关系也不大,不会暴露账号密码 // -DsonatypeUsername=michaelzx -DsonatypePassword=xxxxxx def sonatypeUsername = System.getProperty(“sonatypeUsername”) def sonatypePassword = System.getProperty(“sonatypePassword”) // 打印出来看看,你参数设置对了没 println(“sonatypeUsername:” + sonatypeUsername) println(“sonatypePassword:” + sonatypePassword) url “https://oss.sonatype.org/service/local/staging/deploy/maven2" credentials { // 这里就是之前在issues.sonatype.org注册的账号 // 直接写在不太安全,应该是有办法通过参数,配置到工程之外 username sonatypeUsername password sonatypePassword } } }}signing { sign publishing.publications.mavenJava}javadoc { // <meta http-equiv=“Content-Type” content=“text/html; charset=UTF-8”> // 防止本地打开中文乱码 options.addStringOption(“charset”, “UTF-8”)}在工程根目录下新增gradle.propertiessigning.keyId=密钥keyIdsigning.password=密钥passwordsigning.secretKeyRingFile=私钥keyRingFile路径如果要提交到GitHub上,那么keyId,password好像是暴露了,不过感觉好像也没什么关系,把私钥保护好就好了5、提交到Sonatype仓库首先,用Gradle执行publishToMavenLocal任务,先在本地发布下,看看生成了哪些文件,或还有什么问题然后,用Gradle执行publish任务,发布到指定的maven仓库如果没有报错,那么恭喜你,已经成功提交到了sonatype的仓库中但是提交成功,并不代表发布成功6、到Sonatype OSS发布用你之前注册的账号密码,登录:https://oss.sonatype.org/登录后查看左侧的Build Promotion->Staging Repositories你的提交,会出现在最下面,至于其他是啥,我也不太清楚????Close你的提交在未处理前,是open状态,然后点击Close按钮。一开始不太明白这个Close是啥意思,后来看了下,主要按照中央仓库的要求来验证下你上传到文件签名就是其中一个步骤,会去公钥服务器拉取公钥,然后来验证你所有的文件需要等待一会,等它执行完毕,状态会从open变成closed如果碰到错误的话,仔细看下Activity选项卡,执行了什么步骤,那个步骤出现了什么错误,很清晰的Release一般情况下,感觉如果顺利close后,再次选中点击Release,耐心等待一会,就大功告成了!可以在侧边栏Artifact Search中搜索下你的groupId,此时应该能看到对应的构件名称和版本了7、回复Issue但是很抱歉,到此为止,你的jar包,还不会同步到maven仓库中你需要在你原先创建issue中,告诉下管理人员,你已经完成了第一次发布我用我蹩脚的英文,回复如下:I have already completed the first release.然后管理人员给我回复了:Central sync is activated for org.zhangxiao.paladin2. After you successfully release, your component will be published to Central, typically within 10 minutes, though updates to search.maven.org can take up to two hours.OK,至此,你的构建就会同步到Maven Central Repository了。8、同步需要多久可能你会像我一样很着急,啥时候可以用,怎么还搜不到呢。~ 从sonatype同步到中央仓库,的确是需要一定的时间 不过根据我的观察,文件的同步,会早于索引的同步 比如,比如你等了半天,然后 https://search.maven.org/ 上搜一下依然搜不到那么,你可以去 https://repo1.maven.org/maven2/ 上按照坐标找下,是否能找到你的包如果能找到,那你就可以开始引用它了9、新版本更新只要完成第一个发布,后续就不需要再创建issue了,只要重复5-6步骤可以了。你可以在groupId范围内发布任意名称的构件结束语以前在NPM仓库中发布过自己的东西。相比之下,Maven仓库的发布流程,让人感觉严谨很多。赶紧一起在Maven全球中央仓库中,留下你自己专属的印记吧!一定会让你感觉棒棒的^_^参考文章https://central.sonatype.org/… ...

January 25, 2019 · 2 min · jiezi

阿里高级技术专家:研发效能的追求永无止境

背景大约在5年前,也就是2013年我刚加入阿里的时候,那个时候 DevOps 的风刚吹起来没多久,有家公司宣称能够一天发布几十上百次,这意味着相比传统软件公司几周一次的发布来说,他们响应商业需求的能力可以甩后者几条街,而且这差距根本不是加班能赶上的。今天的 AliExpress 技术团队小几百人的规模,可一天发布几十次也已经司空见惯了,这主要得益于三个方面:非常彻底地微服务化,拆分粒度很细,且旗帜鲜明地反对重二方库。阿里集团整体的运维标准化,尤其是 Docker 技术的全面覆盖。AliExpress SRE 团队不断努力保证稳定性。然而,效能这个东西,你永远不会说:“够了,够快了”,尤其是在当下的消费型社会,人人都是消费者,而消费者恨不得脑子里的欲望刚闪现出来,你的商品或服务瞬间就到他面前。况且,随着我们不断国际化的步伐,新的因素必然会影响原来的高效能。沟通带宽衰减问题第一个因素是研发团队自身的发展和变化,今天的 AliExpress 技术团队已经是一个名副其实的分布式国际化团队,工作地是杭州+深圳+莫斯科+马德里+其他欧亚都市,外籍同学的比例是 15%,而且能看到这个比例会不断提高,新的国外工作地点也会增加。而这样的团队,对比在同一层楼里的一群中国人组成的团队,是有本质的区别的。我们可以将人与人之间的沟通和网络通信做类比,我们知道网络通信是有带宽的,从早期的拨号上网几十K,到现在的家庭宽带主流的几十上百M,再到数据中心内部局域网内部G级别的数量级,带宽越大,能传输的信息也就越多(通常浪费也就越多)。而人与人之间沟通也可以认为是有带宽的,例如充分信任的全由中国工程师组成小团队,平时相互一起吃饭散步聊天,大家彼此都特别了解,沟通起来就特别顺畅,想到一个点子转个朝向说两句对方就懂了。可对于一个分布式国际化团队来说,这个沟通带宽可是衰减得厉害:中文到英文的转换,衰减一次。对于大多数人来说,英语不是母语,沟通的效率自然会降低。单地到多地,衰减一次。电话,视频,钉钉,都没有面对面沟通来的高效。(否则大家都不会不约而同地刷脸了)时差,再衰减一次。杭州和莫斯科的时差是5个小时,所以基本上北京时间上午我们是联系不上莫斯科的同学的。文化的差异,再衰减一次。例如很多我们可以用来增强感情的团建方法,撸串K歌王者吃鸡,外籍同学可能完全不感冒。那有人可能会说,既然沟通成本这么高,那直接在一个地方全部招中国工程师多简单?这么做简单是简单的了,可都这么搞的话,怎么在全球范围吸引优秀的人才呢?更何况 AliExpress 的用户基本都是老外,这后面的人才如果全是中国人,听起来这生意就不太靠谱对不?谷歌微软亚马逊,哪家不是在全世界搜罗顶尖人才?所以说,既然沟通带宽的衰减是难以避免的,那我们唯有把对这带宽的利用率提上去。具体我们已经做了,或者在做一些事情:尽可能和行业主流技术接轨,降低工程师学习成本。我们基于开源 Spring Boot 做的阿里巴巴生态集成,摒弃 antx, webx, pandora,都是这个思路。English First:注释,文档,工具,英文必选,中文可选。服务发现,让所有微服务可见,增强自描述,可搜索。拥抱 Kotlin关于开发效率,我个人认为所有 Java 程序员都应该认认真真、仔仔细细去看下 Kotlin,因为这门语言太简洁了,而且和 Java 可以无缝互操作,完全具备生产环境使用的条件。有关简洁,我这两天把一块 Java 代码改成了 Koltin,在丝毫不降低可读性的情况下(实际上可读性是提高了),代码行妥妥地减少了 1/3 。此外我忍不住分享一下最近我基于 Sergey 的 Kotlin HSF DSL 写的一个将函数发布成 HSF 服务的功能:只需要不到 15 行代码,就可以启动一个 Spring Boot 应用,把一个字符串小写的功能发布成 HSF 服务,大家可以对比下 Java 需要写多少东西。语言层面的升级,给框架,中间件,API设计带来更多的可能性,这就能使我们砍掉更多的所谓脚手架代码,让业务代码更精简,更优雅,进而带来效率提升。作为程序员,如果只掌握一种语言,是非常危险的,因为这种语言的各种设计会禁锢你的思维。我自己会在业余看一些其他语言,不过在日常工作中基本也只能写 Java(如果 shell 也算一种语言的话,还是写过些 shell 的)。不过从现在开始,我会开始尽可能地用 Kotlin 写代码,我的团队也全面把日常编程语言从 Java 切换到 Kotlin,其实我们都已经不算 Early Adoptor 啦,雷卷在一年多前就已经不停在鼓吹 Koltin 并上线了一个应用,AliExpress 俄罗斯办公室的 Sergey 等同学也已经在生产用上了 Kotlin,Sergey 个人也在很多地方分享他的经验。我们会推动 AliExpress 拥抱 Koltin,从语言层面来提升我们的效率。阿里资深技术专家雷卷,在他最近的一篇谈程序员学习的文章中写了很多东西,我都是很认同的,其中一段话尤其想点赞:不要和程序员谈自己的编程历史,很多经验今天已经不适用啦,可能有一些,但是会给别人带来甄别成本,别人也懒得来甄别。2-3年不关注技术,基本快和程序员和编程绝缘啦,不是绝对,但是通常不会错。持续学习,与诸君共勉。FaaSFunction as a Service,又一个新的 Buzz Word?是的,不过我还真的相信这个 Buzz Word,行业里 AWS Lambda, Google Cloud Functions, Microsoft Azure Functions 等服务相继推出,大家都在尝试把自己的业务往上面搬,这其中的道理在哪?如果作为云服务提供商,这个道理是很显而易见。你的对手按照 docker instance 收费,2 core 4g 起,一小时多少钱;如果你能做到按调用次数收费,一小时内运行了 30 次。那这个价格差必然是数量级的,用这一招就可以秒杀对手了。上面所说的纯粹是硬件成本的考量,但我们还需要从效率方面看这个事情。首先由于 Function 天生是无状态的,而且是足够轻量的,那么理论上做到 ms 级别的 auto scaling 是没有问题的,例如 graalvm 就在这方面很有潜力。ms 级别的 auto scaling 不仅能够大幅提升资源利用率,更是提升了运维效率,开发几乎就不再需要考虑容量的事情的。例如在双11的时候,我们做大量的压测,很大程度上是为了保证系统各个部分的水位在预测的安全的线上,如果做到了实时扩缩,那么当流量高峰来的时候再扩容好了。什么是轻量?今天很多工程师可能已经忘了轻量的概念是什么,大家就是各种侵入,写个简单的应用,打出来的 jar 包,业务代码的占比往往不到 1/10。先不说这里可能无谓浪费了多少内存,无谓增加了多少启动时间。这个 client 那个 share 满天飞带来的最麻烦的后果就是,开发经常要做各种升级,而且一升就挂,一查就半天。打着所谓性能旗号的各种重客户端,就是反服务化的;各种缺乏细心设计的 API 导致的不兼容升级(而且是暴力推动,不升级卡发布),就是反工程师操守的。微服务化做得好的,应该积累一大批轻量的接口,使用这些接口甚至都不需要引入什么 share/open/client 的依赖,直接用 HSF 的泛化调用即可,这样的接口才不对用户有代码侵入。我们已经在 AliExpress 尝试(并已经上线)基于 Koltin DSL 和 HSF 泛化调用编写 Function,用户只需要依赖很简单的一个 FaaS SDK 就可以编写业务代码,基于前面提到的阿基米德服务发现,他可以快速重用现有服务,做一些聚合和过滤的操作,满足业务需求,这个在贴近无线的业务中非常有用。当然,这个尝试只是一个开始,但我们已经看到,其实有大量的业务逻辑(在 AliExpress 可能是 5/1 至 1/3)其实自身不依赖于数据,可以做成 Function,而且我们可以做到让这些业务不依赖任何业务二方库,甚至借助 Service Mesh 等技术,不依赖于任何中间件 client。这些业务的 owner 不需要关心各种乱七八糟的升级问题,不需要关心容量问题,真正地只关心自己的业务逻辑。我认为这是 FaaS 该成为的样子,而我及我的团队,正不断努力去实现之。作者介绍许晓斌,阿里高级技术专家,《Maven实战》作者,《Maven权威指南》译者,并合译有《Cucumber:行为驱动开发指南》,曾经负责维护 Maven 中央仓库,参与开发 Maven 仓库管理软件 Sonatype Nexus。曾多次在 ScrumGathering 和 AgileTour 等大会上发表演讲。工作之余喜欢读读人文、跑跑步。本文作者:云效鼓励师阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

January 18, 2019 · 1 min · jiezi

Maven配置覆盖内嵌tomcat虚拟映射路径

Maven配置覆盖内嵌tomcat虚拟映射路径直接配置报错,错误提示如下: Caused by: java.lang.IllegalArgumentException: addChild: Child name ‘/store’ is not unique原因分析:pom.xml的配置并没有覆盖tomcat/conf/server.xml中的配置,导致配置中存在多个相同配置解决方案下载tomcat7-maven-plugin-2.2.jar.zip文件,解压并覆盖本地仓库中的tomcat7-maven-plugin-2.2.jar,比如我的本地仓库在:D:\M2REPO\org\apache\tomcat\maven\tomcat7-maven-plugin\2.2下,那么我们只需要解压并此目录下的tomcat7-maven-plugin-2.2.jar覆盖此文件就ok.pom.xml配置<plugins> <!– 指定jdk1.7编译,否则maven update 可能调整jdk –> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> </configuration> </plugin> <!– tomcat7插件。使用方式:tomcat7:run –> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <update>true</update> <port>8080</port> <uriEncoding>UTF-8</uriEncoding> <server>tomcat7</server> <!– tomcat虚拟映射路径 –> <staticContextPath>/store</staticContextPath> <staticContextDocbase>d:/file/store/</staticContextDocbase> <contextReloadable>false</contextReloadable> <useTestClasspath>true</useTestClasspath> </configuration> </plugin></plugins>参考地址

January 17, 2019 · 1 min · jiezi

springboot+多线程简单实现

搭建springboot环境创建ThreadConfig/** * 线程 * * @author zhoumin * @create 2018-09-18 13:58 /@Configuration@EnableAsyncpublic class ThreadConfig implements AsyncConfigurer{ @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(8); executor.setMaxPoolSize(1000); executor.setQueueCapacity(500); executor.setKeepAliveSeconds(30000); executor.initialize(); return executor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return null; }}创建service和接口void test(int i);service实现类@Override@Asyncpublic void test(int i) { System.out.println(“线程” + Thread.currentThread().getName() + " 执行异步任务:" + i);}测试:@RunWith(SpringRunner.class)@SpringBootTestpublic class BaseTest {}/* * @author zhoumin * @create 2018-09-18 14:12 */public class ThreadTest extends BaseTest{ @Autowired private DeviceStatisticsTaskService deviceStatisticsTaskService; @org.junit.Test public void threadTest() { for (int i = 0; i < 5000; i++) { deviceStatisticsTaskService.test(i); } }} ...

January 17, 2019 · 1 min · jiezi

如何将JAR包发布到Maven中央仓库?

将jar包发布到Maven中央仓库(Maven Central Repository),这样所有的Java开发者都可以使用Maven直接导入依赖,例如fundebug-java:<!– https://mvnrepository.com/artifact/com.fundebug/fundebug-java –><dependency> <groupId>com.fundebug</groupId> <artifactId>fundebug-java</artifactId> <version>0.2.0</version></dependency>但是,Maven中央仓库并不支持直接发布jar包。我们需要将jar包发布到一些指定的第三方Maven仓库,然后该仓库再将jar包同步到Maven中央仓库。其中,最"简单"的方式是通过Sonatype OSSRH仓库来发布jar包。接下来,我会介绍如何将jar包发布到Sonatype OSSRH。本教程所使用的系统配置如下:OS:macOS 10.14.2JDK:1.8.0_192Maven:3.5.41. 注册JIRA账号JIRA是一个项目管理服务,类似于国内的Teambition。Sonatype通过JIRA来管理OSSRH仓库。注册地址:https://issues.sonatype.org/secure/Signup!default.jspa需要填写Email, Full Name, Username以及password,其中Username与Password后面的步骤需要用到,请记下来。2. 创建issue通过在JIRA上创建issue来申请发布新的jar包,Sonatype的工作人员会进行审核,审核不算严格,一般按照要求填写不会有问题。创建链接:https://issues.sonatype.org/secure/CreateIssue.jspa?issuetype=21&pid=10134创建issue的时候需要填写下面这些信息:SummaryDescriptionGroup IdProject URLSCM url大家可以参考我申请发布fundebug-java与fundebug-spring时所填写的内容:OSSRH-45238由于时差,前一天创建issue,第二天早上才会有回应。当issue的status变为RESOLVED,我们就可以进行下一步操作了。3. 安装并配置GPG发布到Maven仓库中的所有文件都要使用GPG签名,以保障完整性。因此,我们需要在本地安装并配置GPG。安装GPGMacBook安装GPG非常简单,下载并安装GPG Suite即可。生成GPG密钥对gpg –gen-key生成密钥时将需要输入name、email以及password。password在之后的步骤需要用到,请记下来。上传GPG公钥将公钥上传到公共的密钥服务器,这样其他人才可以通过公钥来验证jar包的完整性。gpg –keyserver hkp://keyserver.ubuntu.com:11371 –send-keys CAB4165C69B699D989D2A62BD74A11D3F9F41243其中CAB4165C69B699D989D2A62BD74A11D3F9F41243为密钥的ID,可以通过gpg –list-keys命令查看gpg –list-keys/Users/kiwenlau/.gnupg/pubring.kbx———————————-pub dsa2048 2010-08-19 [SC] [expires: 2020-06-15] 85E38F69046B44C1EC9FB07B76D78F0500D026C4uid [ unknown] GPGTools Team <team@gpgtools.org>sub elg2048 2010-08-19 [E] [expires: 2020-06-15]sub rsa4096 2014-04-08 [S] [expires: 2024-01-02]pub rsa2048 2019-01-03 [SC] [expires: 2021-01-02] CAB4165C69B699D989D2A62BD74A11D3F9F41243uid [ultimate] kiwenlau <kiwenlau@gmail.com>sub rsa2048 2019-01-03 [E] [expires: 2021-01-02]4. 配置Maven的setting.xmlsetting.xml为Maven的全局配置文件,在MacBook上的位置为/usr/local/Cellar/maven/3.5.4/libexec/conf/settings.xml,我们需要将第1步配置的Username和Password添加到<servers></servers>标签中,这样我们才能将jar包部署到Sonatype OSSRH仓库:<servers> <server> <id>ossrh</id> <username>Fundebug</username> <password>passsword</password> </server></servers>5. 配置项目的pom.xmlpom.xml挺长的。根据Sonatype OSSRH的要求,以下信息都必须配置:Supply Javadoc and SourcesSign Files with GPG/PGPSufficient MetadataCorrect CoordinatesProject Name, Description and URLLicense InformationDeveloper InformationSCM Information配置时参考我的pom.xml,根据需要修改即可。<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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.fundebug</groupId> <artifactId>fundebug-java-notifier</artifactId> <version>0.2.0</version> <packaging>pom</packaging> <name>fundebug-java-notifier</name> <url>https://github.com/Fundebug/fundebug-java-notifier</url> <description>Capture Java and Spring exceptions automatically</description> <licenses> <license> <name>Server Side Public License</name> <url>https://www.mongodb.com/licensing/server-side-public-license</url> <distribution>repo</distribution> <comments>A not business-friendly OSS license</comments> </license> </licenses> <scm> <url>https://github.com/Fundebug/fundebug-java-notifier</url> <connection>https://github.com/Fundebug/fundebug-java-notifier.git</connection> </scm> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.deploy.skip>true</maven.deploy.skip> </properties> <developers> <developer> <name>kiwenlau</name> <id>kiwenlau</id> <email>kiwenlau@gmail.com</email> <roles> <role>Developer</role> </roles> <timezone>+8</timezone> </developer> </developers> <profiles> <profile> <id>default</id> <activation> <activeByDefault>true</activeByDefault> </activation> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.2.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>jar-no-fork</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-javadoc-plugin</artifactId> <version>2.9.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-gpg-plugin</artifactId> <version>1.6</version> <executions> <execution> <phase>verify</phase> <goals> <goal>sign</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <distributionManagement> <snapshotRepository> <id>ossrh</id> <url>https://oss.sonatype.org/content/repositories/snapshots/</url> </snapshotRepository> <repository> <id>ossrh</id> <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> </repository> </distributionManagement> </profile> </profiles> <modules> <module>fundebug-java</module> <module>fundebug-spring</module> <module>examples/hello-world</module> <module>examples/spring-rest-api</module> </modules></project>6. 发布jar包执行mvn clean deploy处理,即可将jar包发布到Sonatype OSSRH仓库。mvn clean deploy -projects fundebug-java,fundebug-spring 我们的项目fundebug-java-notifier含有多个模块,仅需部署fundebug-java与fundebug-spring,因此使用-projects选项来指定。第一次执行mvn clean deploy命令时,需要输入GPG密钥的密码。mvn clean deploy命令执行成功的输出是这样的(部分日志):[INFO] ————————————————————————[INFO] Reactor Summary:[INFO][INFO] fundebug-java 0.2.0 ………………………….. SUCCESS [ 22.183 s][INFO] fundebug-spring 0.2.0 ………………………… SUCCESS [ 16.383 s][INFO] ————————————————————————[INFO] BUILD SUCCESS[INFO] ————————————————————————[INFO] Total time: 38.728 s[INFO] Finished at: 2019-01-12T20:10:16+08:00[INFO] ————————————————————————7. close并releasemvn clean deploy命令执行成功,使用JIRA账号登陆:https://oss.sonatype.org/#stagingRepositories,就可以看到你所发布的jar包了:选中对于的repository之后,点击箭头所指的close,close时会检查发布的构件是否符合要求。若符合要求,则close成功,成功之后点击箭头所指的release,即可正式将jar包发布到Sonatype OSSRH仓库。release成功大概2个小时之后,该构件就会同步到Maven中央仓库:参考Guide to uploading artifacts to the Central RepositoryOSSRH GuideMaven入门教程关于FundebugFundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了9亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用!版权声明转载时请注明作者Fundebug以及本文地址:https://blog.fundebug.com/2019/01/14/how-to-deploy-jar-to-maven-central-repository/ ...

January 14, 2019 · 2 min · jiezi

teamcity开疆扩土---自动部署maven项目到linux服务器并重启tomcat

前言teamcity是一款非常强大的cicd(持续集成,持续发布)工具,和jenkins非常类似。但个人觉得比jenkins好用。网上有很多部署teamcity的博客。我参考的是这篇:https://www.jianshu.com/p/255…正题上图是teamcity的主界面图。点击红框的地方创建项目填写信息,点击process修改项目名,一般可跳过重点来了,构建步骤第一步:第二步:第三步:脚本:cd /opt/tomcat_8081/bin/kill -s 9 $(netstat -tlnp | grep :8081 | awk ‘{print $7}’ | awk -F ‘/’ ‘{print $1}’)./startup.sh开始部署填坑总结得到上面三个步骤还是踩过不少的坑。我记录了下来。无法从中央仓库下载maven的插件答:发生这个问题的时候,是因为我使用了代理作为出外网的工具。具体原因我现在还是没有解决。只能自己部署teamcity在联网的服务器上解决。删除掉了配置文件,但war中依旧包含了旧的配置文件答:第一步的 clean 绝对不能少文件传输的位置不对

January 11, 2019 · 1 min · jiezi

最小化 Java 镜像的常用技巧

背景随着容器技术的普及,越来越多的应用被容器化。人们使用容器的频率越来越高,但常常忽略一个基本但又非常重要的问题 - 容器镜像的体积。本文将介绍精简容器镜像的必要性并以基于 spring boot 的 java 应用为例描述最小化容器镜像的常用技巧。精简容器镜像的必要性精简容器镜像是非常必要的,下面分别从安全性和敏捷性两个角度进行阐释。安全性基于安全方面的考虑,将不必要的组件从镜像中移除可以减少攻击面、降低安全风险。虽然 docker 支持用户通过 Seccomp 限制容器内可以执行操作或者使用 AppArmor 为容器配置安全策略,但它们的使用门槛较高,要求用户具备安全领域的专业素养。敏捷性精简的容器镜像能提高容器的部署速度。假设某一时刻访问流量激增,您需要通过增加容器副本数以应对突发压力。如果某些宿主机不包含目标镜像,需要先拉取镜像,然后启动容器,这时使用体积较小的镜像能加速这一过程、缩短扩容时间。另外,镜像体积越小,其构建速度也越快,同时还能减少存储和传输的成本。常用技巧将一个 java 应用容器化所需的步骤可归纳如下:编译 java 源码并生成 jar 包。将应用 jar 包和依赖的第三方 jar 包移动到合适的位置。本章所用的样例是一个基于 spring boot 的 java 应用 spring-boot-docker,所用的未经优化的 dockerfile 如下:FROM maven:3.5-jdk-8COPY src /usr/src/app/srcCOPY pom.xml /usr/src/appRUN mvn -f /usr/src/app/pom.xml clean packageENTRYPOINT [“java”,"-jar","/usr/src/app/target/spring-boot-docker-1.0.0.jar"]由于应用使用 maven 构建,dockerfile 中指定maven:3.5-jdk-8作为基础镜像,该镜像的大小为 635MB。通过这种方式最终构建出的镜像非常大,达到了 719MB,这是因为一方面基础镜像本身就很大,另一方面 maven 在构建过程中会下载许多用于执行构建任务的 jar 包。多阶段构建Java 程序的运行只依赖 JRE,并不需要 maven 或者 JDK 中众多用于编译、调试、运行的工具,因此一个明显的优化方法是将用于编译构建 java 源码的镜像和用于运行 java 应用的镜像分开。为了达到这一目的,在 docker 17.05 版本之前需要用户维护 2 个 dockerfile 文件,这无疑增加了构建的复杂性。好在自 17.05 开始,docker 引入了多阶段构建的概念,它允许用户在一个 dockerfile 中使用多个 From 语句。每个 From 语句可以指定不同的基础镜像并将开启一个全新的构建流程。您可以选择性地将前一阶段的构建产物复制到另一个阶段,从而只将必要的内容保留在最终的镜像里。优化后的 dockerfile 如下:FROM maven:3.5-jdk-8 AS buildCOPY src /usr/src/app/srcCOPY pom.xml /usr/src/appRUN mvn -f /usr/src/app/pom.xml clean packageFROM openjdk:8-jreARG DEPENDENCY=/usr/src/app/target/dependencyCOPY –from=build ${DEPENDENCY}/BOOT-INF/lib /app/libCOPY –from=build ${DEPENDENCY}/META-INF /app/META-INFCOPY –from=build ${DEPENDENCY}/BOOT-INF/classes /appENTRYPOINT [“java”,"-cp",“app:app/lib/”,“hello.Application”]该 dockerfile 选用maven:3.5-jdk-8作为第一阶段的构建镜像,选用openjdk:8-jre作为运行 java 应用的基础镜像并且只拷贝了第一阶段编译好的.claass文件和依赖的第三方 jar 包到最终的镜像里。通过这种方式优化后的镜像大小为 459MB。使用 distroless 作为基础镜像虽然通过多阶段构建能减小最终生成的镜像的大小,但 459MB 的体积仍相对过大。经调查发现,这是因为使用的基础镜像openjdk:8-jre体积过大,到达了 443MB,因此下一步的优化方向是减小基础镜像的体积。Google 开源的项目 distroless 正是为了解决基础镜像体积过大这一问题。Distroless 镜像只包含应用程序及其运行时依赖项,不包含包管理器、shell 以及在标准 Linux 发行版中可以找到的任何其他程序。目前,distroless 为依赖 java、python、nodejs、dotnet 等环境的应用提供了基础镜像。使用 distroless 的 dockerfile 如下:FROM maven:3.5-jdk-8 AS buildCOPY src /usr/src/app/srcCOPY pom.xml /usr/src/appRUN mvn -f /usr/src/app/pom.xml clean packageFROM gcr.io/distroless/javaARG DEPENDENCY=/usr/src/app/target/dependencyCOPY –from=build ${DEPENDENCY}/BOOT-INF/lib /app/libCOPY –from=build ${DEPENDENCY}/META-INF /app/META-INFCOPY –from=build ${DEPENDENCY}/BOOT-INF/classes /appENTRYPOINT [“java”,"-cp",“app:app/lib/”,“hello.Application”]该 dockerfile 和上一版的唯一区别在于将运行阶段依赖的基础镜像由openjdk:8-jre(443 MB)替换成了gcr.io/distroless/java(119 MB)。经过这一优化,最终镜像的大小为 135MB。使用 distroless 的唯一不便是您无法 attach 到一个正在运行的容器上排查问题,因为镜像中不包含 shell。虽然 distroless 的 debug 镜像提供 busybox shell,但需要用户重新打包镜像、部署容器,对于那些已经基于非 debug 镜像部署的容器无济于事。 但从安全角度来看,无法 attach 容器并不完全是坏事,因为攻击者无法通过 shell 进行攻击。使用 alpine 作为基础镜像如果您确实有 attach 容器的需求,又希望最小化镜像的大小,可以选用 alpine 作为基础镜像。Alpine 镜像的特点是体积非常下,基础款镜像的体积仅 4 MB 左右。使用 alpine 后的 dockerfile 如下:FROM maven:3.5-jdk-8 AS buildCOPY src /usr/src/app/srcCOPY pom.xml /usr/src/appRUN mvn -f /usr/src/app/pom.xml clean packageFROM openjdk:8-jre-alpineARG DEPENDENCY=/usr/src/app/target/dependencyCOPY –from=build ${DEPENDENCY}/BOOT-INF/lib /app/libCOPY –from=build ${DEPENDENCY}/META-INF /app/META-INFCOPY –from=build ${DEPENDENCY}/BOOT-INF/classes /appENTRYPOINT [“java”,"-cp",“app:app/lib/*”,“hello.Application”]这里并未直接继承基础款 alpine,而是选用从 alpine 构建出的包含 java 运行时的openjdk:8-jre-alpine(83MB)作为基础镜像。使用该 dockerfile 构建出的镜像体积为 99.2MB,比基于 distroless 的还要小。执行命令docker exec -ti <container_id> sh可以成功 attach 到运行的容器中。distroless vs alpine既然 distroless 和 alpine 都能提供非常小的基础镜像,那么在生产环境中到底应该选择哪一种呢?如果安全性是您的首要考虑因素,建议选用 distroless,因为它唯一可运行的二进制文件就是您打包的应用;如果您更关注镜像的体积,可以选用 alpine。其他技巧除了可以通过上述技巧精简镜像外,还有以下方式:将 dockerfile 中的多条指令合并成一条,通过减少镜像层数的方式达到精简镜像体积的目的。将稳定且体积较大的内容置于镜像下层,将变动频繁且体积较小的内容置于镜像上层。虽然该方式无法直接精简镜像体积,但充分利用了镜像的缓存机制,同样可以达到加快镜像构建和容器部署的目的。想了解更多优化 dockerfile 的小窍门可参考教程 Best practices for writing Dockerfiles。总结本文通过一系列的优化,将 java 应用的镜像体积由最初的 719MB 缩小到 100MB 左右。如果您的应用依赖其他环境,也可以用类似的原则进行优化。针对 java 镜像,google 提供的另一款工具 jib 能为您屏蔽镜像构建过程中的复杂细节,自动构建出精简的 java 镜像。使用它您无须编写 dockerfile,甚至不需要安装 docker。对于类似 distroless 这样无法 attach 或者不方便 attach 的容器,建议您将它们的日志中心化存储,以便问题的追踪和排查。具体方法可参考文章面向容器日志的技术实践。本文作者:吴波bruce_wu阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

January 11, 2019 · 2 min · jiezi

maven基本概念详解思维导图版

今天整理了关于maven的知识点,瞬间清晰了好多。都是自己辛苦整理的,详情在processon

January 9, 2019 · 1 min · jiezi

Fundebug后端Java异常监控插件更新至0.2.0,支持Spring及Maven

摘要: 0.2.0支持监控Spring应用,并且支持使用Maven接入插件,请大家及时更新。支持监控Spring应用1. pom.xml配置fundebug-spring依赖<dependency> <groupId>com.fundebug</groupId> <artifactId>fundebug-spring</artifactId> <version>0.2.0</version></dependency>2. 在项目中引入fundebug并配置apikey新增FundebugConfig.javaimport org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Import;import com.fundebug.Fundebug;import com.fundebug.SpringConfig;@Configuration@Import(SpringConfig.class)public class FundebugConfig { @Bean public Fundebug getBean() { return new Fundebug(“apikey”); }}注意:获取apikey需要免费注册帐号并且创建项目。可以参考Demo项目Fundebug/fundebug-spring-demo。支持使用Maven接入插件Fundebug的Java异常监控插件fundebug-java与fundebug-spring都发布到了Maven中央仓库,因此可以在pom.xml直接配置依赖。接入fundebug-java<dependency> <groupId>com.fundebug</groupId> <artifactId>fundebug-java</artifactId> <version>0.2.0</version></dependency>接入fundebug-spring<dependency> <groupId>com.fundebug</groupId> <artifactId>fundebug-spring</artifactId> <version>0.2.0</version></dependency>参考Fundebug文档 - JavaMaven入门教程关于FundebugFundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了9亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用!版权声明转载时请注明作者Fundebug以及本文地址:https://blog.fundebug.com/2019/01/07/fundebug-java-0-2-0/

January 8, 2019 · 1 min · jiezi

在 CentOS 7 上搭建 Jenkins + Maven + Git 持续集成环境

本文以部署 Spring boot + Maven 项目为例,使用码云作为代码托管仓库,在 CentOS 7 上搭建 Jenkins 持续集成环境。1. 准备工作1.1 安装 Java 环境Jenkins 是基于 Java 开发的持续集成工具,需要在 Java 环境下运行。用下面命令查看系统是否已安装 Java:yum list installed | grep jdk如果没有,使用 yum search 命令查找 openjdk 版本,选择合适的 jdk 进行安装:yum search openjdk yum -y install java-1.8.0-openjdk-devel验证 Java 是否安装成功:java -version1.2 安装 Maven依次运行以下两条命令:wget http://repos.fedorapeople.org… -O /etc/yum.repos.d/epel-apache-maven.repo yum -y install apache-maven验证 Maven 是否安装成功:mvn -v1.3 安装 Git直接通过 yum 安装,安装完成后查看版本验证是否安装成功:yum -y install git git –version2. 安装和配置 Jenkins:2.1 安装 Jenkins依次运行以下三条命令:sudo wget https://pkg.jenkins.io/redhat… -O /etc/yum.repos.d/jenkins.repo sudo rpm –import https://pkg.jenkins.io/redhat… yum -y install jenkins如果之前从 Jenkins 导入过 key,那么 rpm –import 将失败,因为已经有一个 key 了。忽略它,继续执行 install 即可。2.2 启动 Jenkins启动 Jenkins,并且设置开机自启动:systemctl start jenkins.service chkconfig jenkins onJenkins 默认使用8080端口,访问以下链接即可看到 Jenkins 的 Web 界面:http://&lt;服务器地址>:8080如果无法访问,检查一下防护墙,是否有开放端口,或使用命令 netstat -ntulp 查看端口是否被占用。2.3 进入 Jenkins首次进入 Jenkins 需要输入管理员密码,使用以下命令查看初始密码:cat /var/lib/jenkins/secrets/initialAdminPassword选择默认的 install suggested plugins 安装插件,等待安装完成后依照步骤创建用户,创建完成后即可登入。2.4 配置 Jenkins进入 Manage Jenkins -> Global Tool Configuration,依次配置 JDK、Git 和 Maven 路径。2.4.1 查看 JDK 路径使用 yum 安装的软件不会帮我们配置环境变量,直接使用命令echo $JAVA_HOME 是看不到路径的。 先用以下命令查看路径:which java看到的结果是 /usr/bin/java ,但实际上这只是个软连接,并不是 JDK 真正的所在目录。 继续使用以下命令查看:ls -l /usr/bin/java看到 /usr/bin/java 指向了 /etc/alternatives/java,很遗憾,还不是我们要找的真正路径。 继续追踪:ls -l /etc/alternatives/java结果指向了 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-1.el7_6.x86_64/jre/bin/java,不同版本的 JDK 目录名可能有些不同,这就是 JDK 真正所在的地方。 同理可获得 Maven 的所在路径。2.4.2 安装和配置插件进入 Manage Jenkins -> Manage Plugins,搜索并安装 Publish Over SSH 和 Maven Integration 两个插件, Git Plugins 插件已经默认安装上了,我们无需再安装。配置 SSH 免密码登录 在配置插件之前,我们先在 Jenkins 服务器上生成密钥对。运行以下命令切换到 jenkins 用户:sudo su jenkins如果无法切换,则打开 /etc/passwd 文件,找到 jenkins 那一行,将 /bin/fasle 改成 /bin/bash。 切换成功后,命令提示符的用户名可能是 bash-4.2$,想要正常显示用户名的话,先切换回 root 用户,执行以下操作:编辑文件 vi /.bash_profile 加入语句 export PS1=’[u@h W]&dollar;’ 立即生效 source /.bash_profile再切换到 jenkins 用户,就显示正常了。接下来运行以下命令生成密钥对:ssh-keygen -t rsa一路按回车完成,会在 /var/lib/jenkins/.ssh/ 目录下生成 id_rsa 和 id_rsa.pub两个文件。 将 id_rsa.pub 文件里的内容追加到应用服务器上的 /root/.ssh/authorized_keys 文件末尾,每行一个 key,注意是应用服务器。重启应用服务器上的 ssh 服务:systemctl restart sshd.service现在 Jenkins 可以免密码登录应用服务器了,以 jenkins 用户身份运行命令来测试一下:ssh root@<应用服务器地址>首次连接会有确认提示,输入 yes 即可。这步很重要,如果第一次没有手动连接确认,Jenkins 会连不上。配置 Public over SSH 插件 进入 Manage Jenkins -> Configure System,填写 Publish over SSH 设置。Path to key:填写刚刚生成的 id_rsa 密钥文件的路径。 Name:服务名,随意填写。 HostName:应用服务器的 IP 地址或域名。 Username:登录应用服务器的用户身份。 Remote Directory:远程目录, 应用服务器上存放应用的目录,Jenkins 会把应用拷贝至此目录下。请确保此目录存在。save3. 部署 Maven 项目点击 New Item 新建任务,随意输入任务名,选择 Maven project, ok。 在General,勾选 Discard old builds,可以设置最多保留构建文件多少天,和最多保留多少个构建文件,不然每次构建生成的文件都会保留,占用磁盘空间。 配置远程代码仓库地址,Jenkins 会从该地址拉取代码。注意此处如果提示无法读取仓库,有可能是:公钥没有添加到远程代码服务器的 authorized_keys 文件里,上面配置 SSH 免登录是 Jenkins 访问应用服务器的,Jenkins 访问代码服务器也同样需要配置,除非应用服务器和代码服务器是同一台机器。如果使用码云或 GitHub 等代码托管平台,会有相应的 SSH key 设置页。公钥已添加到相应文件里,但没有手动连接第一次。解决方法很简单,以 jenkins 用户身份手动 clone 一次仓库,确认 yes 即可。勾选 Add timestamps to the Console Output,在控制台输出构建过程。填写 Maven 打包指令,-DMaven.test.skip=true 表示跳过测试。勾选 Run only if build succeeds,选择 Send files or execute commands over SSH。接下来就是设置 build 完之后,把 jar 包从 Jenkins 服务器拷贝到应用服务器上,并运行。Name:选择之前创建的服务。 Source files:maven 打包后生成的 jar 包,即要拷贝到应用服务器运行的程序,可填多个,英文逗号分隔。 Remove prefix:忽略前缀,我们只需要拷贝 target 下的 jar 包,不需要在应用服务器上生成 target 目录。 Remote directory:目标文件夹,会继承全局设置,例如此处会把 jar 包拷贝到 /usr/local/app/demo 目录下。 Exec command:拷贝完成后,在应用服务器上执行的命令或脚本。save -> build now,构建成功后,打开浏览器访问你的站点吧4. 总结其实整个流程不是很复杂,Jenkins 从远程代码库拉取代码 -> 调用 maven 指令将项目打包 -> Jenkins 将打包好的文件拷贝到远程应用服务器 -> 在远程应用服务器上执行 shell 指令,启动程序。其中 Jenkins 两次远程操作都是通过 SSH 完成的。 通过 yum 安装 Jenkins 和 Java 比较方便,但是在配置的时候相对麻烦,安装路径要自己找,配置 SSH 的时候也是要用 jenkins 用户身份,而不是 root,如果采用解压缩包的方式就比较自由一些。 ...

January 3, 2019 · 2 min · jiezi

使用Maven Helper解决Maven插件冲突

1、何为依赖冲突Maven是个很好用的依赖管理工具,但是再好的东西也不是完美的。Maven的依赖机制会导致Jar包的冲突。举个例子,现在你的项目中,使用了两个Jar包,分别是A和B。现在A需要依赖另一个Jar包C,B也需要依赖C。但是A依赖的C的版本是1.0,B依赖的C的版本是2.0。这时候,Maven会将这1.0的C和2.0的C都下载到你的项目中,这样你的项目中就存在了不同版本的C,这时Maven会依据依赖路径最短优先原则,来决定使用哪个版本的Jar包,而另一个无用的Jar包则未被使用,这就是所谓的依赖冲突。在大多数时候,依赖冲突可能并不会对系统造成什么异常,因为Maven始终选择了一个Jar包来使用。但是,不排除在某些特定条件下,会出现类似找不到类的异常,所以,只要存在依赖冲突,在我看来,最好还是解决掉,不要给系统留下隐患。2、解决方法解决依赖冲突的方法,就是使用Maven提供的<exclusion>标签,<exclusion>标签需要放在<exclusions>标签内部,就像下面这样:<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.10.0</version> <exclusions> <exclusion> <artifactId>log4j-api</artifactId> <groupId>org.apache.logging.log4j</groupId> </exclusion> </exclusions></dependency>log4j-core本身是依赖了log4j-api的,但是因为一些其他的模块也依赖了log4j-api,并且两个log4j-api版本不同,所以我们使用<exclusion>标签排除掉log4j-core所依赖的log4j-api,这样Maven就不会下载log4j-core所依赖的log4j-api了,也就保证了我们的项目中只有一个版本的log4j-api。3、Maven Helper看到这里,你可能会有一个疑问。如何才能知道自己的项目中哪些依赖的Jar包冲突了呢?Maven Helper这个InteliJ IDEA的插件帮我们解决了这个问题。插件的安装方法我就不讲了,既然你都会Maven了,我相信你也是会安装插件的。在插件安装好之后,我们打开pom.xml文件,在底部会多出一个Dependency Analyzer选项点开这个选项找到冲突,点击右键,然后选择Exclude即可排除冲突版本的Jar包。4、小技巧除了使用Maven Helper查看依赖冲突,也可以使用IDEA提供的方法——Maven依赖结构图,打开Maven窗口,选择Dependencies,然后点击那个图标(Show Dependencies)或者使用快捷键(Ctrl+Alt+Shift+U),即可打开Maven依赖关系结构图在图中,我们可以看到有一些红色的实线,这些红色实线就是依赖冲突,蓝色实线则是正常的依赖。若文章有任何问题,欢迎留言指出——作者博客:桔子笔记

December 28, 2018 · 1 min · jiezi

Python进阶:自定义对象实现切片功能

Python进阶:自定义对象实现切片功能切片是 Python 中最迷人最强大最 Amazing 的语言特性(几乎没有之一),在《Python进阶:切片的误区与高级用法》中,我介绍了切片的基础用法、高级用法以及一些使用误区。这些内容都是基于原生的序列类型(如字符串、列表、元组……),那么,我们是否可以定义自己的序列类型并让它支持切片语法呢?更进一步,我们是否可以自定义其它对象(如字典)并让它支持切片呢?1、魔术方法:getitem()想要使自定义对象支持切片语法并不难,只需要在定义类的时候给它实现魔术方法 getitem() 即可。所以,这里就先介绍一下这个方法。语法: object.getitem(self, key)官方文档释义:Called to implement evaluation of self[key]. For sequence types, the accepted keys should be integers and slice objects. Note that the special interpretation of negative indexes (if the class wishes to emulate a sequence type) is up to the getitem() method. If key is of an inappropriate type, TypeError may be raised; if of a value outside the set of indexes for the sequence (after any special interpretation of negative values), IndexError should be raised. For mapping types, if key is missing (not in the container), KeyError should be raised.概括翻译一下:getitem() 方法用于返回参数 key 所对应的值,这个 key 可以是整型数值和切片对象,并且支持负数索引;如果 key 不是以上两种类型,就会抛 TypeError;如果索引越界,会抛 IndexError ;如果定义的是映射类型,当 key 参数不是其对象的键值时,则会抛 KeyError 。2、自定义序列实现切片功能接下来,我们定义一个简单的 MyList ,并给它加上切片功能。(PS:仅作演示,不保证其它功能的完备性)。class MyList(): def init(self): self.data = [] def append(self, item): self.data.append(item) def getitem(self, key): print(“key is : " + str(key)) return self.data[key]l = MyList()l.append(“My”)l.append(“name”)l.append(“is”)l.append(“Python猫”)print(l[3])print(l[:2])print(l[‘hi’])### 输出结果:key is : 3Python猫key is : slice(None, 2, None)[‘My’, ’name’]key is : hiTraceback (most recent call last):…TypeError: list indices must be integers or slices, not str从输出结果来看,自定义的 MyList 既支持按索引查找,也支持切片操作,这正是我们的目的。特别需要说明的是,此例中的 getitem() 方法会根据不同的参数类型而实现不同的功能(取索引位值或切片值),也会妥当地处理异常,所以并不需要我们再去写繁琐的处理逻辑。网上有不少学习资料完全是在误人子弟,它们会教你区分参数的不同类型,然后写一大段代码来实现索引查找和切片语法,简直是画蛇添足。下面的就是一个代表性的错误示例:###略去其它代码####def getitem(self, index): cls = type(self) if isinstance(index, slice): # 如果index是个切片类型,则构造新实例 return cls(self.components[index]) elif isinstance(index, numbers.Integral): # 如果index是个数,则直接返回 return self.components[index] else: msg = “{cls.name} indices must be integers” raise TypeError(msg.format(cls=cls))3、自定义字典实现切片功能切片是序列类型的特性,所以在上例中,我们不需要写切片的具体实现逻辑。但是,对于其它非序列类型的自定义对象,就得自己实现切片逻辑。以自定义字典为例(PS:仅作演示,不保证其它功能的完备性):class MyDict(): def init(self): self.data = {} def len(self): return len(self.data) def append(self, item): self.data[len(self)] = item def getitem(self, key): if isinstance(key, int): return self.data[key] if isinstance(key, slice): slicedkeys = list(self.data.keys())[key] return {k: self.data[k] for k in slicedkeys} else: raise TypeErrord = MyDict()d.append(“My”)d.append(“name”)d.append(“is”)d.append(“Python猫”)print(d[2])print(d[:2])print(d[-4:-2])print(d[‘hi’])### 输出结果:is{0: ‘My’, 1: ’name’}{0: ‘My’, 1: ’name’}Traceback (most recent call last):…TypeError上例的关键点在于将字典的键值取出,并对键值的列表做切片处理,其妙处在于,不用担心索引越界和负数索引,将字典切片转换成了字典键值的切片,最终实现目的。4、小结最后小结一下:本文介绍了__getitem() 魔术方法,并用于实现自定义对象(以列表类型和字典类型为例)的切片功能,希望对你有所帮助。参考阅读: Python进阶:切片的误区与高级用法官方文档getitem用法:http://t.cn/EbzoZypPython切片赋值源码分析:http://t.cn/EbzSaoZPS:本公众号(Python猫)已开通读者交流群,详情请通过菜单栏中的“交流群”来了解。—————–本文原创并首发于微信公众号【Python猫】,后台回复“爱学习”,免费获得20+本精选电子书。 ...

December 27, 2018 · 2 min · jiezi

maven3.6.0安装后执行mvn -v出现no goals

[INFO] Scanning for projects…[INFO] ————————————————————————[INFO] BUILD FAILURE[INFO] ————————————————————————[INFO] Total time: 0.140 s[INFO] Finished at: 2018-12-23T22:25:01+08:00[INFO] ————————————————————————[ERROR] No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1][ERROR][ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.[ERROR] Re-run Maven using the -X switch to enable full debug logging.[ERROR][ERROR] For more information about the errors and possible solutions, please read the following articles:[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/NoGoalSpecifiedException执行mvn -v报上面的错误解决方案在安装目录下找到lib/maven-model-builder-3.6.0.jar选择使用压缩包打开,根据这个目录META-INFmavenorg.apache.mavenmaven-model-builder找到pom.xml然后找到第一个build,在后面添加<defaultGoal>compile</defaultGoal>然后一路保存即可 ...

December 23, 2018 · 1 min · jiezi

Nexus-Maven私服搭建

前言????????????本次分享Nexus-Maven私服Linux环境搭建。关于Nexus的作用相信大家都有所了解,在这里就不做详细说明了。总之使用Nexus可以大大的提高开发效率。如果还有对 Maven及Nexus 不太了解的同学,请自行百度。????Nexus下载下载地址 : Nexus选择对应版本下载完成wget方式以上浏览器访问官网下载方式,可以在Linux服务器直接使用wget方式替代wget https://sonatype-download.global.ssl.fastly.net/nexus/3/nexus-3.14.0-04-unix.tar.gz安装配置切换到 usr/local/cd usr/local/创建 nexus 目录mkdir nexus将之前下载的压缩安装包上传到服务器解压安装包tar -xzvf nexus-3.14.0-04-unix.tar.gz切换到 nexus-3.14.0-04 目录cd nexus-3.14.0-04切换到 bin 目录cd bin启动 nexus./nexus startnexus 默认端口 8081 关于端口及配置可以到 Nexus 下 /etc/nexus-default.properties 该配置中进行修改具体port 及 context-path配置验证成果浏览器访问 htttp://xxx.xxx.xxx.xxx:8081点击 sign in 进行登录 初始用户名及密码: admin/admin123如果Nexus正常启动,浏览器访问不了Nexus。检查Linux服务器防火墙 8081 端口是否开放iptables 开放8081端口 iptables -A INPUT -p tcp –dport 8081 -j ACCEPT 重启iptables service iptables restart firewall 开放 8081 端口 firewall-cmd –zone=public –add-port=8081/tcp –permanent 重启iptables firewall-cmd –reload 结束语以上就是Nexus的安装配置,关于Nexus具体的使用静待后期分享。✔ END© ???????? ???? ????????????

December 18, 2018 · 1 min · jiezi

在maven离线模式使用intellij idea的配置

今天在内网使用intellij idea,把maven仓库也拷贝了过来,但是使用maven install 命令的时候,却还是从私服里面下载。(内网无法连接到任何私服)导致install的时候报缺少依赖的错误。经过各种搜索,终于发现了解决办法。 ...

June 11, 2018 · 1 min · jiezi