vue组件之间的通信

安装 vue-bus

npm install vue-bus --save-dev

创建 vue-bus

/**
* 组件之间的通信
* @param Vue
*/
const install = (Vue) =>{
  const Bus = new Vue({
      methods:{
          emit(event, ...args){
              this.$emit(event, ...args)
          },
          on (event, callback){
              this.$on(event, callback)
          },
          off(event, callback){
              this.$off(event, callback)
          }
      }
  })
  Vue.prototype.$bus = Bus
}
export default install

index.js

import VueBus from '@/common/vue-bus'
Vue.use(VueBus)

组件a 调用 组件b

# 组件 a
let num = Math.floor(Math.random() * 100 + 1);
this.$bus.$emit('getMenu', num);

# 组件 b
,created() {
    this.$bus.$on('getMenu', target => {
        // console.log(target);
        this.getMenus();
    });
}

RPC入门总结 RPC定义和原理

一、RPC

1. RPC是什么

    RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。
2. 为什么要用RPC? 
其实这是应用开发到一定的阶段的强烈需求驱动的。

    1. 如果我们开发简单的单一应用,逻辑简单、用户不多、流量不大,那我们用不着;

    2. 当我们的系统访问量增大、业务增多时,我们会发现一台单机运行此系统已经无法承受。此时,我们可以将业务拆分成几个互不关联的应用,分别部署在各自机器上,以划清逻辑并减小压力。此时,我们也可以不需要RPC,因为应用之间是互不关联的。
    3. 当我们的业务越来越多、应用也越来越多时,自然的,我们会发现有些功能已经不能简单划分开来或者划分不出来。此时,可以将公共业务逻辑抽离出来,将之组成独立的服务Service应用 。而原有的、新增的应用都可以与那些独立的Service应用 交互,以此来完成完整的业务功能。所以此时,我们急需一种高效的应用程序之间的通讯手段来完成这种需求,所以你看,RPC大显身手的时候来了!
    其实3描述的场景也是服务化 、微服务 和分布式系统架构 的基础场景。即RPC框架就是实现以上结构的有力方式。

二、RPC的原理和框架

Nelson 的论文中指出实现 RPC 的程序包括 5 个部分:

1. User

2. User-stub

3. RPCRuntime

4. Server-stub

5. Server

    这里 user 就是 client 端,当 user 想发起一个远程调用时,它实际是通过本地调用user-stub。user-stub 负责将调用的接口、方法和参数通过约定的协议规范进行编码并通过本地的 RPCRuntime 实例传输到远端的实例。远端 RPCRuntime 实例收到请求后交给 server-stub 进行解码后发起本地端调用,调用结果再返回给 user 端。
    RPC 服务方通过 RpcServer 去导出(export)远程接口方法,而客户方通过 RpcClient 去引入(import)远程接口方法。客户方像调用本地方法一样去调用远程接口方法,RPC 框架提供接口的代理实现,实际的调用将委托给代理RpcProxy 。代理封装调用信息并将调用转交给RpcInvoker 去实际执行。在客户端的RpcInvoker 通过连接器RpcConnector 去维持与服务端的通道RpcChannel,并使用RpcProtocol 执行协议编码(encode)并将编码后的请求消息通过通道发送给服务方。
    RPC 服务端接收器 RpcAcceptor 接收客户端的调用请求,同样使用RpcProtocol 执行协议解码(decode)。解码后的调用信息传递给RpcProcessor 去控制处理调用过程,最后再委托调用给RpcInvoker 去实际执行并返回调用结果。如下是各个部分的详细职责:
    1. RpcServer  
       负责导出(export)远程接口  
    2. RpcClient  
       负责导入(import)远程接口的代理实现  
    3. RpcProxy  
       远程接口的代理实现  
    4. RpcInvoker  
       客户方实现:负责编码调用信息和发送调用请求到服务方并等待调用结果返回  
       服务方实现:负责调用服务端接口的具体实现并返回调用结果  
    5. RpcProtocol  
       负责协议编/解码  
    6. RpcConnector  
       负责维持客户方和服务方的连接通道和发送数据到服务方  
    7. RpcAcceptor  
       负责接收客户方请求并返回请求结果  
    8. RpcProcessor  
       负责在服务方控制调用过程,包括管理调用线程池、超时时间等  
    9. RpcChannel  
       数据传输通道  

三、Java中常用的RPC框架

目前常用的RPC框架如下:

1. Thrift:thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。

2. Dubbo:Dubbo是一个分布式服务框架,以及SOA治理方案。其功能主要包括:高性能NIO通讯及多协议集成,服务动态寻址与路由,软负载均衡与容错,依赖分析与降级等。 Dubbo是阿里巴巴内部的SOA服务化治理方案的核心框架,Dubbo自2011年开源后,已被许多非阿里系公司使用。 

3. Spring Cloud:Spring Cloud由众多子项目组成,如Spring Cloud Config、Spring Cloud Netflix、Spring Cloud Consul 等,提供了搭建分布式系统及微服务常用的工具,如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性token、全局锁、选主、分布式会话和集群状态等,满足了构建微服务所需的所有解决方案。Spring Cloud基于Spring Boot, 使得开发部署极其简单。

四、RPC和消息队列的差异

1. 功能差异

    在架构上,RPC和Message的差异点是,Message有一个中间结点Message Queue,可以把消息存储。
    消息的特点
    1. Message Queue把请求的压力保存一下,逐渐释放出来,让处理者按照自己的节奏来处理。
    2. Message Queue引入一下新的结点,系统的可靠性会受Message Queue结点的影响。
    3. Message Queue是异步单向的消息。发送消息设计成是不需要等待消息处理的完成。
    所以对于有同步返回需求,用Message Queue则变得麻烦了。
RPC的特点
    同步调用,对于要等待返回结果/处理结果的场景,RPC是可以非常自然直觉的使用方式(RPC也可以是异步调用)。
    由于等待结果,Consumer(Client)会有线程消耗。如果以异步RPC的方式使用,Consumer(Client)线程消耗可以去掉。但不能做到像消息一样暂存消息/请求,压力会直接传导到服务Provider。
    2. 适用场合差异
        1. 希望同步得到结果的场合,RPC合适。
        2. 希望使用简单,则RPC;RPC操作基于接口,使用简单,使用方式模拟本地调用。异步的方式编程比较复杂。
        3. 不希望发送端(RPC Consumer、Message Sender)受限于处理端(RPC Provider、Message Receiver)的速度时,使用Message Queue。
        随着业务增长,有的处理端处理量会成为瓶颈,会进行同步调用到异步消息的改造。这样的改造实际上有调整业务的使用方式。比如原来一个操作页面提交后就下一个页面会看到处理结果;改造后异步消息后,下一个页面就会变成“操作已提交,完成后会得到通知”。
    3. 不适用场合说明
        1. RPC同步调用使用Message Queue来传输调用信息。 上面分析可以知道,这样的做法,发送端是在等待,同时占用一个中间点的资源。变得复杂了,但没有对等的收益。
        2. 对于返回值是void的调用,可以这样做,因为实际上这个调用业务上往往不需要同步得到处理结果的,只要保证会处理即可。(RPC的方式可以保证调用返回即处理完成,使用消息方式后这一点不能保证了。)
        3. 返回值是void的调用,使用消息,效果上是把消息的使用方式Wrap成了服务调用(服务调用使用方式成简单,基于业务接口)。

五、RPC框架的核心技术点

RPC框架实现的几个核心技术点:

(1)服务暴露:

    远程提供者需要以某种形式提供服务调用相关的信息,包括但不限于服务接口定义、数据结构、或者中间态的服务定义文件。例如Facebook的Thrift的IDL文件,Web service的WSDL文件;服务的调用者需要通过一定的途径获取远程服务调用相关的信息。

    目前,大部分跨语言平台 RPC 框架采用根据 IDL 定义通过 code generator 去生成 stub 代码,这种方式下实际导入的过程就是通过代码生成器在编译期完成的。代码生成的方式对跨语言平台 RPC 框架而言是必然的选择,而对于同一语言平台的 RPC 则可以通过共享接口定义来实现。这里的导入方式本质也是一种代码生成技术,只不过是在运行时生成,比静态编译期的代码生成看起来更简洁些。

    java 中还有一种比较特殊的调用就是多态,也就是一个接口可能有多个实现,那么远程调用时到底调用哪个?这个本地调用的语义是通过 jvm 提供的引用多态性隐式实现的,那么对于 RPC 来说跨进程的调用就没法隐式实现了。如果前面DemoService 接口有 2 个实现,那么在导出接口时就需要特殊标记不同的实现需要,那么远程调用时也需要传递该标记才能调用到正确的实现类,这样就解决了多态调用的语义问题。

(2)远程代理对象:

    服务调用者用的服务实际是远程服务的本地代理。说白了就是通过动态代理来实现。

    java 里至少提供了两种技术来提供动态代码生成,一种是 jdk 动态代理,另外一种是字节码生成。动态代理相比字节码生成使用起来更方便,但动态代理方式在性能上是要逊色于直接的字节码生成的,而字节码生成在代码可读性上要差很多。两者权衡起来,个人认为牺牲一些性能来获得代码可读性和可维护性显得更重要。

(3)通信:

    RPC框架与具体的协议无关。RPC 可基于 HTTP 或 TCP 协议,Web Service 就是基于 HTTP 协议的 RPC,它具有良好的跨平台性,但其性能却不如基于 TCP 协议的 RPC。

    1. TCP/HTTP:众所周知,TCP 是传输层协议,HTTP 是应用层协议,而传输层较应用层更加底层,在数据传输方面,越底层越快,因此,在一般情况下,TCP 一定比 HTTP 快。

    2. 消息ID:RPC 的应用场景实质是一种可靠的请求应答消息流,和 HTTP 类似。因此选择长连接方式的 TCP 协议会更高效,与 HTTP 不同的是在协议层面我们定义了每个消息的唯一 id,因此可以更容易的复用连接。

    3. IO方式:为了支持高并发,传统的阻塞式 IO 显然不太合适,因此我们需要异步的 IO,即 NIO。Java 提供了 NIO 的解决方案,Java 7 也提供了更优秀的 NIO.2 支持。

    4. 多连接:既然使用长连接,那么第一个问题是到底 client 和 server 之间需要多少根连接?实际上单连接和多连接在使用上没有区别,对于数据传输量较小的应用类型,单连接基本足够。单连接和多连接最大的区别在于,每根连接都有自己私有的发送和接收缓冲区,因此大数据量传输时分散在不同的连接缓冲区会得到更好的吞吐效率。所以,如果你的数据传输量不足以让单连接的缓冲区一直处于饱和状态的话,那么使用多连接并不会产生任何明显的提升,反而会增加连接管理的开销。
    5. 心跳:连接是由 client 端发起建立并维持。如果 client 和 server 之间是直连的,那么连接一般不会中断(当然物理链路故障除外)。如果 client 和 server 连接经过一些负载中转设备,有可能连接一段时间不活跃时会被这些中间设备中断。为了保持连接有必要定时为每个连接发送心跳数据以维持连接不中断。心跳消息是 RPC 框架库使用的内部消息,在前文协议头结构中也有一个专门的心跳位,就是用来标记心跳消息的,它对业务应用透明。

(4)序列化:

    两方面会直接影响 RPC 的性能,一是传输方式,二是序列化。

    1. 序列化方式:毕竟是远程通信,需要将对象转化成二进制流进行传输。不同的RPC框架应用的场景不同,在序列化上也会采取不同的技术。 就序列化而言,Java 提供了默认的序列化方式,但在高并发的情况下,这种方式将会带来一些性能上的瓶颈,于是市面上出现了一系列优秀的序列化框架,比如:Protobuf、Kryo、Hessian、Jackson 等,它们可以取代 Java 默认的序列化,从而提供更高效的性能。

    2. 编码内容:出于效率考虑,编码的信息越少越好(传输数据少),编码的规则越简单越好(执行效率高)。如下是编码需要具备的信息:

    -- 调用编码 --  
    1. 接口方法  
       包括接口名、方法名  
    2. 方法参数  
       包括参数类型、参数值  
    3. 调用属性  
       包括调用属性信息,例如调用附件隐式参数、调用超时时间等  

    -- 返回编码 --  
    1. 返回结果  
       接口方法中定义的返回值  
    2. 返回码  
       异常返回码  
    3. 返回异常信息  
       调用异常信息 

    除了以上这些必须的调用信息,我们可能还需要一些元信息以方便程序编解码以及未来可能的扩展。这样我们的编码消息里面就分成了两部分,一部分是元信息、另一部分是调用的必要信息。如果设计一种 RPC 协议消息的话,元信息我们把它放在协议消息头中,而必要信息放在协议消息体中。下面给出一种概念上的 RPC 协议消息设计格式:

    -- 消息头 --  
    magic      : 协议魔数,为解码设计  
    header size: 协议头长度,为扩展设计  
    version    : 协议版本,为兼容设计  
    st         : 消息体序列化类型  
    hb         : 心跳消息标记,为长连接传输层心跳设计  
    ow         : 单向消息标记,  
    rp         : 响应消息标记,不置位默认是请求消息  
    status code: 响应消息状态码  
    reserved   : 为字节对齐保留  
    message id : 消息 id  
    body size  : 消息体长度  

    -- 消息体 --  
    采用序列化编码,常见有以下格式  
    xml   : 如 webservie soap  
    json  : 如 JSON-RPC  
    binary: 如 thrift; hession; kryo 等  

Springboot 使用注解@Validated和BindingResult校验参数

1、创建一个参数对象

# Validation
package common.validate.type
    public class Validation {

    /**查询*/
    public interface Select {
    }
    /**更新*/
    public interface Update {
    }
    /**插入*/
    public interface Insert {
    }
    /**删除*/
    public interface Delete {
    }

    /**查询详情*/
    public interface SelectDetail {
    }

}

import java.util.List;
import common.validate.type.Validation;

import javax.validation.constraints.Min;
import javax.validation.constraints.Size;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;

public class Parameter {

    @NotEmpty(message="姓名不能为空", groups = Validation.Update.class)
    private String name;

    @Min(value = 18, message = "年龄必须大于18岁", groups = Validation.Update.class)
    private int age;

    @NotEmpty(message="hobbies不能为空", groups = Validation.Update.class)
    private List<String> hobbies;

    @NotBlank(message="账号不能为空", groups = Validation.Update.class)
    private String account;

    @Size(min=5,max=10,message="密码的长度应该在5和10之间", groups = Validation.Update.class) 
    private String password;

    @Email(message="邮箱格式错误", groups = Validation.Update.class)
    private String email;

    // Getter and Setter
    // ... 

}

2、controller控制层写参数接收的入口

public class BaseController {
    /**
    * 正常的返回值
    *
    * @param outPutBean
    */
    protected void setSuccess(BaseVO outPutBean) {
        outPutBean.setResultCode(ConstantsRecruit.ResultCode.SUCCESS);
    }

    /**
    * 处理参数异常
    *
    * @param bindingResult
    */
    protected void paramaterVidation(BindingResult bindingResult) throws Exception {
        if (bindingResult.hasErrors()) {
            StringBuilder errorMesssage = new StringBuilder("参数异常:");
            for (FieldError fieldError : bindingResult.getFieldErrors()) {
                errorMesssage.append(fieldError.getField());
                errorMesssage.append(":");
                errorMesssage.append(fieldError.getDefaultMessage());
                errorMesssage.append("; ");
            }
            throw new TestAplException(ConstantsRecruit.ResultCode.PARAM_ERR, errorMesssage.toString());
        }
    }
}


# 注意:BindingResult需要放到@Validated后面

public class TestController extends BaseController{

    @ApiOperation(value = "测试", notes = "更新")
    @PostMapping(value = "/update")
    public BaseVO update(@RequestBody @Validated(Validation.Update.class) Parameter input,BindingResult bindingResult){
        paramaterVidation(bindingResult);
        BaseVO vo = new BaseVO();
        commonService.update();
        setSuccess(vo);
        return vo;
    }
}

3、常用校验注解

@Null 只能是null
@NotNull 不能为null 注意用在基本类型上无效,基本类型有默认初始值
@AssertFalse 必须为false
@AssertTrue 必须是true

字符串/数组/集合检查:(字符串本身就是个数组)
@Pattern(regexp=”reg”) 验证字符串满足正则
@Size(max, min) 验证字符串、数组、集合长度范围
@NotEmpty 验证字符串不为空或者null
@NotBlank 验证字符串不为null或者trim()后不为空

数值检查:同时能验证一个字符串是否是满足限制的数字的字符串
@Max 规定值得上限int
@Min 规定值得下限
@DecimalMax(“10.8”) 以传入字符串构建一个BigDecimal,规定值要小于这个值
@DecimalMin 可以用来限制浮点数大小
@Digits(int1, int2) 限制一个小数,整数精度小于int1;小数部分精度小于int2
@Digits 无参数,验证字符串是否合法
@Range(min=long1,max=long2) 检查数字是否在范围之间
这些都包括边界值

日期检查:Date/Calendar
@Post 限定一个日期,日期必须是过去的日期
@Future 限定一个日期,日期必须是未来的日期

其他验证:
@Vaild 递归验证,用于对象、数组和集合,会对对象的元素、数组的元素进行一一校验
@Email 用于验证一个字符串是否是一个合法的右键地址,空字符串或null算验证通过
@URL(protocol=,host=,port=,regexp=,flags=) 用于校验一个字符串是否是合法URL

Maven 安装和配置

Maven 资料

Maven 安装(bash 环境)

  • Maven 3.3 的 JDK 最低要求是 JDK 7
  • 下载压缩包:wget http://mirrors.cnnic.cn/apache/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz
  • 解压:tar zxvf apache-maven-3.3.9-bin.tar.gz
  • 修改目录名,默认的太长了:mv apache-maven-3.3.9/ maven3.3.9/
  • 移到我个人习惯的安装目录下:mv maven3.3.9/ /usr/local
  • 环境变量设置:vim /etc/profile
  • 在文件最尾巴添加下面内容:
1
2
3
4
5
6
7
8
9
# Maven
MAVEN_HOME=/usr/local/maven3.3.9
M3_HOME=/usr/local/maven3.3.9
PATH=$PATH:$M3_HOME/bin
MAVEN_OPTS="-Xms256m -Xmx356m"
export M3_HOME
export MAVEN_HOME
export PATH
export MAVEN_OPTS
  • 刷新配置文件:source /etc/profile
  • 测试是否安装成功:mvn -version

Maven 配置

  • 创建本地参数:mkdir -p /opt/maven-repository
  • 配置项目连接上私服
  • 编辑配置文件:vim /usr/local/maven3.3.9/conf/settings.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?xml version="1.0" encoding="UTF-8"?>

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">

<!--本地仓库位置-->
<localRepository>/opt/maven-repository</localRepository>

<pluginGroups>
</pluginGroups>

<proxies>
</proxies>

<!--设置 Nexus 认证信息-->
<servers>
<server>
<id>nexus-releases</id>
<username>admin</username>
<password>admin123</password>
</server>
<server>
<id>nexus-snapshots</id>
<username>admin</username>
<password>admin123</password>
</server>
</servers>

<!--有自己的 nexus 改为自己的-->
<mirrors>
<mirror>
<id>aliyun-releases</id>
<mirrorOf>*</mirrorOf>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</mirror>
<mirror>
<id>aliyun-snapshots</id>
<mirrorOf>*</mirrorOf>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</mirror>
</mirrors>

</settings>

资料

Maven deploy file 上传 pom

mvn deploy:deploy-file -DgroupId= -DartifactId= -Dversion= -Dpackaging=jar -Dfile=<Path_TO_JAR_OR_WAR> -DrepositoryId=<RepositoryId_defined_in_settings_xml> -Durl= -DgeneratePom=true -DpomFile=<PATH_TO_POM>

Maven deploy file 上传 jar

mvn install:install-file -Dfile=E:\jar\org.apache.poi.xwpf.converter.xhtml-1.0.5.jar -DgroupId=fr.opensagres.xdocreport -DartifactId=org.apache.poi.xwpf.converter.xhtml -Dversion=1.0.5 -Dpackaging=jar

例子

deploy pom

mvn deploy:deploy-file -DgroupId=com.huapisong.parent -DartifactId=com_base_parent -Dversion=1.0.0-RELEASE -Dpackaging=pom -Dfile=E:\com_base_parent-1.0.0-RELEASE.pom -DrepositoryId=huapisong -Durl=http://localhost:9090/repository/huapisong/ -DgeneratePom=true

deploy jar

mvn deploy:deploy-file -DgroupId=com.huapisong.common -DartifactId=com_base_common -Dversion=1.0.0-RELEASE -Dpackaging=jar -Dfile=E:\com_base_common-1.0.0-RELEASE.jar -DrepositoryId=huapisong -Durl=http://localhost:9090/repository/huapisong/

install 命令,file 参数是必选的,但是如果在本地库里面没有 groupId、artifactId 和 version 对应的目录,那么 maven 会要求传入这些参数,packaging 则根据需要上传的文件类型指定。
deploy 命令 file、repositoryId 和 url 是必选的。其中 DrepositoryId 是指远程 maven 库的 id,一般会配置在 setting.xml 文件里面,是在标签下的那个 id。url 比较重要,如果错误的话,是无法上传的,一般来说我们可以在 setting.xml 文件的标签下找到,但是这个下的这个 url 不一定就是真正的 maven 库地址,如果这个 url 不行,那么可以尝试把这个 url 中的最后一个路径替换成标签下自标签的内容,一般来说是可以行的

Maven 命令参数

备注
mvn -v –version 显示版本信息;
mvn -V –show-version 显示版本信息后继续执行Maven其他目标;
mvn -h –help 显示帮助信息;
mvn -e –errors 控制Maven的日志级别,产生执行错误相关消息;
mvn -X –debug 控制Maven的日志级别,产生执行调试信息;
mvn -q –quiet 控制Maven的日志级别,仅仅显示错误;
mvn -Pxxx 激活 id 为 xxx的profile (如有多个,用逗号隔开);
mvn -Dxxx=yyy 指定Java全局属性;
mvn -o –offline 运行offline模式,不联网更新依赖;
mvn -N –non-recursive 仅在当前项目模块执行命令,不构建子模块;
mvn -pl –module_name 在指定模块上执行命令;
mvn -ff –fail-fast 遇到构建失败就直接退出;
mvn -fn –fail-never 无论项目结果如何,构建从不失败;
mvn -fae –fail-at-end 仅影响构建结果,允许不受影响的构建继续;
mvn -C –strict-checksums 如果校验码不匹配的话,构建失败;
mvn -c –lax-checksums 如果校验码不匹配的话,产生告警;
mvn -U 强制更新snapshot类型的插件或依赖库(否则maven一天只会更新一次snapshot依赖);
mvn -npu –no-plugin-s 对任何相关的注册插件,不进行最新检查(使用该选项使Maven表现出稳定行为,该稳定行为基于本地仓库当前可用的所有插件版本);
mvn -cpu –check-plugin-updates 对任何相关的注册插件,强制进行最新检查(即使项目POM里明确规定了Maven插件版本,还是会强制更新);
mvn -up –update-plugins [mvn -cpu]的同义词;
mvn -B –batch-mode 在非交互(批处理)模式下运行(该模式下,当Mven需要输入时,它不会停下来接受用户的输入,而是使用合理的默认值);
mvn -f –file 强制使用备用的POM文件;
mvn -s –settings 用户配置文件的备用路径;
mvn -gs –global-settings 全局配置文件的备用路径;
mvn -emp –encrypt-master-password 加密主安全密码,存储到Maven settings文件里;
mvn -ep –encrypt-password 加密服务器密码,存储到Maven settings文件里;
mvn -npr –no-plugin-registry 对插件版本不使用~/.m2/plugin-registry.xml(插件注册表)里的配置;

Node 安装和配置

Node 安装

1
2
3
4
5
6
# 如果你是要安装 node 8 系列,下载这个 yum 源
curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -
# 如果你是要安装 node 9 系列,下载这个 yum 源
curl --silent --location https://rpm.nodesource.com/setup_9.x | sudo bash -
# 然后通过 yum 开始安装(软件大小:51M 左右)
sudo yum -y install nodejs
  • 验证:node -v
  • 注意:因为网络原因,最好先把脚本下载到本地,再用代理进行安装

nrm 快速切换 NPM 源

String 的反转

package com.example.demo;

import java.util.Stack;

/**
 * String 的反转
 */
public class Reverse {
    private String str = null;

    public Reverse(String str) {
        this.str = str;
    }

    // 数组实现String反转
    public String reverseByArray() {
        if (str == null || str.length() == 1) {
            return str;
        }
        char[] ch = str.toCharArray();// 字符串转换成字符数组
        for (int i = 0; i < ch.length / 2; i++) {
            char temp = ch[i];
            ch[i] = ch[ch.length - i - 1];
            ch[ch.length - i - 1] = temp;
        }
        return new String(ch);
    }

    // 用栈实现String反转
    public String reverseByStack() {
        if (str == null || str.length() == 1) {
            return str;
        }
        Stack<Character> stack = new Stack<Character>();
        char[] ch = str.toCharArray();// 字符串转换成字符数组
        for (char c : ch) {
            stack.push(c);// 每个字符,推进栈
        }
        for (int i = 0; i < ch.length; i++) {
            ch[i] = stack.pop();// 移除这个堆栈的顶部对象
        }
        return new String(ch);
    }

    // 用逆序遍历实现String反转
    public String reverseBySort() {
        if (str == null || str.length() == 1) {
            return str;
        }
        StringBuffer sb = new StringBuffer();
        for (int i = str.length() - 1; i >= 0; i--) {
            sb.append(str.charAt(i));// 使用StringBuffer从右往左拼接字符
        }
        return sb.toString();
    }

    // 使用位运算实现String反转
    public String reverseByBit() {
        if (str == null || str.length() == 1) {
            return str;
        }
        char[] ch = str.toCharArray();// 字符串转换成字符数组
        int len = str.length();
        for (int i = 0; i < len / 2; i++) {
            ch[i] ^= ch[len - 1 - i];
            ch[len - 1 - i] ^= ch[i];
            ch[i] ^= ch[len - 1 - i];
        }
        return new String(ch);
    }

    //使用递归实现String反转
    public String reverseByRecursive(String str) {
        if (str == null || str.length() == 0) {
            return str;
        }
        if (str.length() == 1) {
            return str;
        } else {
            // 从下标为1开始截取字符串,在返回下标为0的字符
            return reverseByRecursive(str.substring(1)) + str.charAt(0);
        }
    }

    // 使用 StringBuilder reverse() 方法反转
    public String reverseByStringBuilder(String str) {
        if (str == null || str.length() == 0) {
            return str;
        }
        StringBuilder sb = new StringBuilder(str);
        return sb.reverse().toString();
    }

    public static void main(String[] args) {
        String s = "123456";

        Reverse r = new Reverse(s);
        System.out.println(r.reverseByArray());
        System.out.println(r.reverseByStack());
        System.out.println(r.reverseBySort());
        System.out.println(r.reverseByBit());
        System.out.println(r.reverseByRecursive(s));
        System.out.println(r.reverseByStringBuilder(s));
    }
}

maven使用简单介绍

官网:http://maven.apache.org/

详细教程:https://www.w3cschool.cn/maven/

简单使用maven做什么

  • 提供了项目对象模型(POM)文件来管理项目的构建。
  • 仓库的搜索顺序为:本地仓库、中央仓库、远程仓库。

    1
    2
    3
    本地仓库用来存储项目的依赖库;
    中央仓库是下载依赖库的默认位置;
    远程仓库,因为并非所有的库存储在中央仓库,或者中央仓库访问速度很慢,远程仓库是中央仓库的补充。
  • 构建不依赖于IDE的标准化项目(导入IDE只需要以maven项目导入即可)

  • 目录结构统一并且简单,约定大于配置,被其他构建工具以及项目广泛采用
  • 统一对项目依赖的jar包进行管理,明确jar包依赖以及对应的版本自动下载等(细节请看详细教程

maven的下载安装

1. 下载

进入官网选择download菜单进入下载页面
image
tar.gz文件对应linux系统
zip文件对应windows系统

2. 安装

解压即可使用  
对于在windows下使用maven,如果需要使用cmd执行命令的话,需要在path环境变量中添加maven/bin目录即可,使用IDE并不需要配置环境变量等  
推荐目录结构如下:

image

第一个为解压后的文件目录  
第二个用来作为maven的全局文件(settings.xml)存放目录(IDE中需要在maven配置中指向此文件才会生效,日后更换maven版本只需要更换原来的maven解压路径即可,不必再做配置)  
第三个用来作为maven下载jar包的本地仓库存放目录(需要在settings.xml配置文件中指定,不然存放到默认路径C盘中,不方便管理与查找)  

3. 配置

在解压的文件目录下进入conf文件夹,其中有默认的settings.xml配置文件
image
配置文件一般只需要配置2个地方,一个是下载jar包的本地仓库存放目录,另外一个为下载jar包的国内镜像地址(默认地址为国外,速度较慢)
image
从默认的注释中复制出来,配置上前面定好的本地仓库存放目录,如果不配置则会存放到注释中默认指向地址${user.home}/.m2/repository
image
依旧从默认的注释中复制镜像出来,id与name可以随意起名,mirrorOf为central则说明是中央仓库,URL推荐填写阿里云maven仓库地址 http://maven.aliyun.com/nexus/content/groups/public
之后保存,复制出一份存放在前面设置的maven全局文件存放目录下面(当替换maven版本时,内置的配置文件使用IDE设置好全局文件时可不用更改,更换maven版本也只是解压新版本后在IDE中设置新的maven安装路径就完成了)

IDE中配置maven

  1. MyEclipse
    点击导航栏window进入preferences搜索maven
    image
    建议勾选Download Artifact Sources(下载jar包的同时下载源码,方便直接点方法进源码查看)
    image
    添加安装的maven
    image
    设置好maven的全局配置文件路径(本地仓库存放目录自动扫描文件中的目录)
    至此完成了MyEclipse中maven的配置

  2. IDEA
    不要在打开项目的时候选择file/settings,那样设置完只会针对当前项目,若打开了项目,则选择file/Close Project关闭项目回退到初始idea界面

image
image
指定好maven的安装目录以及配置文件位置
image
image
至此完成了idea中的maven的配置

创建一个maven的java web项目

  1. MyEclipse
    image
    image
    选取项目模板java web项目为maven-archetype-webapp
    image
    image
    finish完成创建,第一次创建时需要下载一些jar包,会慢一点,至此就创建完毕了

  2. IDEA
    新建项目
    image
    image
    image
    image
    finish完成创建,第一次创建时需要下载一些jar包,会慢一点,至此就创建完毕了

maven的java web项目的目录结构

pom.xml项目配置文件例子,包含普通项目所需jar包引入,行间内置注释
文件目录结构

```
project
│   pom.xml(maven项目配置文件)
│
└───src(源码根目录)
│   │
│   └───main(源码主目录)
│   │   │
│   │   └───java(java源码目录)
│   │   │   │
│   │   │   └───xxx(项目包名)
│   │   │   └───sql(包名,有清空数据库在java源码目录下同级放置)
│   │   │
│   │   └───resources(源码所使用的资源文件目录,存放配置文件)
│   │   │   │
│   │   │   └───config(配置文件)
│   │   │        │
│   │   │        └───jdbc
│   │   │        └───mybatis
│   │   │        └───spring
│   │   │
│   │   └───webapp(web文件目录,等同于WebRoot)
│   │   │
│   │
│   └───test(测试目录,测试用例等,小项目暂未使用)
│        │   xxxTest.java
│        │   ...
│    
└───target(maven项目默认编译输出目录,自动生成)
          │   ...
```  
  1. java源码目录使用模板生成没有此文件夹,自行创建并设置为源码目录,MyEclipse设置方式为文件夹右键Build Path/Use as Source Folder,idea为右键Make Directory as/Sources Root
  2. resources资源文件目录在导入maven项目时此文件夹为普通文件夹,需要IDE设置为资源文件夹,MyEclipse设置方式同上,idea为右键Make Directory as/Resources Root
  3. 如果需要引入特殊jar包(第三方支付等),跟以前方式一致
  4. 旧项目转化为maven项目,按照上述创建一个maven项目,直接打开2边的文件夹,直接拷贝到相应地方,删除多余jar包以及原来多余编译生成的文件即可,无需其余操作,反之把maven项目转化也一样(需要把编译目录下的jar包拷过去)

javamelody java系统监控插件

pom.xml

<!-- java系统监控插件 -->
    <dependency>
        <groupId>net.bull.javamelody</groupId>
        <artifactId>javamelody-core</artifactId>
        <version>1.60.0</version>
    </dependency>

# Configuration.java

import net.bull.javamelody.MonitoringFilter;
import net.bull.javamelody.SessionListener;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 *
 * @author zqs
 * @since
 */
@Configuration
public class JavamelodyConfiguration {
    @Bean
    public FilterRegistrationBean monitorFilter(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MonitoringFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;
    }

    @Bean
    public ServletListenerRegistrationBean sessionListener(){
        ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean();
        servletListenerRegistrationBean.setListener(new SessionListener());
        return servletListenerRegistrationBean;
    }
}   

普通javaweb项目

导入jar包:
javamelody.jar
jrobin-1.5.14.jar
启动项目的时候监控系统自动启动,无需配置(jdk1.7,tomcat 7 环境下);

访问:http://主机地址:端口号/项目名/monitoring

右键添加Notepad2

1、 首先打开注册表,windows+ R运行,在运行窗口中输入regedit,进入注册表编辑器
2、 在左边的导航中找到路径:HKEY_CLASSES_ROOT*\shell
3、 在shell上右键,新建项,命名为Notepad2
4、 在新建的项Notepad2上右键,然后新建一个项,命名为command,新建了command之后选中command项会发现右边有相应的值,双击默认进行修改
5、 双击默认后对其值进行修改,先写Notepad2的路径,然后写上“%1”,点击确定 例:”E:\software\TortoiseGit\bin\notepad2.exe” “%1”