关于一次JVM宕机的问题排查

描述

情况是这样的,tomcat服务刚启动访问正常, 但是过不了一会儿,访问就N慢,到最后服务直接宕机.

处理

1. 先打印tomcat日志,看看什么情况: tail -200f logs/proj.log

   堆内存溢出,JVM荣幸挂了.
2.接下来: 看看内存的使用情况
    先找到java线程pid, 然后执行: jmap -heap [pid]

    JVM总共分配了3G内存, 怎么一下子就耗光了, Eden space/Old Generation都是满的.
    所以断定: 再往上加内存是没用了, 肯定是代码问题, 某个方法一次性加载了大量的数据导致.
    于是,我们就要做dump分析了
3.DUMP内存情况
    >jmap -dump:live,format=b,file=/tmp/dump20170603.bin [pid]
    dump文件一共3G,还好不大.
4.分析dump文件
    我用MAT(memory analyzer tool)分析工具: 先设置-Xmx4g,要不然撑不住.
   
    DubboServerHandler占了1.0G
    JDBC4ResultSet占了1.4G
    看了一下DubboServerHandler,  里面最大的对象也是JDBC4ResultSet.
    所以, 这是典型的SQL结果集太大, 没做分页处理.  到底是那个SQL???
    
    再分析ResultSet所属的Statement对象,终于找到了这个罪犯: select * from 用户表;
    后面居然没有加任何条件,没有加!!! 把所有用户都查出来…..顿时吴宇森!
    之后,在分析这个线程具体调用的堆栈信息,发现是: 查询别的业务时,附带查询的用户信息.
    
    用户查询本身有加条件做为输入参数,但是方法里面, 并没有为条件做空判断.
    导致: 条件为空时,便查询了所有用户.  

总结

缺少一个条件判断,导致整个服务宕机. 多么狗血的事实.

常用SQL

1. 行列转换--普通

假设有张学生成绩表(CJ)如下
Name Subject Result
张三 语文 80
张三 数学 90
张三 物理 85
李四 语文 85
李四 数学 92
李四 物理 82

想变成
姓名 语文 数学 物理
张三 80 90 85
李四 85 92 82

declare @sql varchar(4000)
set @sql = 'select Name'
select @sql = @sql + ',sum(case Subject when '''+Subject+''' then Result end) ['+Subject+']'
from (select distinct Subject from CJ) as a
select @sql = @sql+' from test group by name'
exec(@sql)

2. 行列转换--合并

有表A,
id pid
1 1
1 2
1 3
2 1
2 2
3 1
如何化成表B:
id pid
1 1,2,3
2 1,2
3 1

创建一个合并的函数
create function fmerg(@id int)
returns varchar(8000)
as
begin
declare @str varchar(8000)
set @str=''
select @str=@str+','+cast(pid as varchar) from 表A where id=@id set @str=right(@str,len(@str)-1)
return(@str)
End
go

--调用自定义函数得到结果
select distinct id,dbo.fmerg(id) from 表A

3. 如何取得一个数据表的所有列名

方法如下:先从SYSTEMOBJECT系统表中取得数据表的SYSTEMID,然后再SYSCOLUMN表中取得该数据表的所有列名。
SQL语句如下:
declare @objid int,@objname char(40)
set @objname = 'tablename'
select @objid = id from sysobjects where id = object_id(@objname)
select 'Column_name' = name from syscolumns where id = @objid order by colid

是不是太简单了? 呵呵 不过经常用阿.

4. 通过SQL语句来更改用户的密码

修改别人的,需要sysadmin role
EXEC sp_password NULL, 'newpassword', 'User'

如果帐号为SA执行EXEC sp_password NULL, 'newpassword', sa

5. 怎么判断出一个表的哪些字段不允许为空?

select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where IS_NULLABLE='NO' and TABLE_NAME=tablename

6. 如何在数据库里找到含有相同字段的表?
a. 查已知列名的情况
SELECT b.name as TableName,a.name as columnname
From syscolumns a INNER JOIN sysobjects b
ON a.id=b.id
AND b.type='U'
AND a.name='你的字段名字'

b. 未知列名查所有在不同表出现过的列名
Select o.name As tablename,s1.name As columnname
From syscolumns s1, sysobjects o
Where s1.id = o.id
And o.type = 'U'
And Exists (
Select 1 From syscolumns s2
Where s1.name = s2.name
And s1.id <> s2.id
)

7. 查询第xxx行数据

假设id是主键:
select *
from (select top xxx * from yourtable) aa
where not exists(select 1 from (select top xxx-1 * from yourtable) bb where aa.id=bb.id)

如果使用游标也是可以的
fetch absolute [number] from [cursor_name]
行数为绝对行数

8. SQL Server日期计算
a. 一个月的第一天
SELECT DATEADD(mm, DATEDIFF(mm,0,getdate()), 0)
b. 本周的星期一
SELECT DATEADD(wk, DATEDIFF(wk,0,getdate()), 0)
c. 一年的第一天
SELECT DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)
d. 季度的第一天
SELECT DATEADD(qq, DATEDIFF(qq,0,getdate()), 0)
e. 上个月的最后一天
SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(mm,0,getdate()), 0))
f. 去年的最后一天
SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0))
g. 本月的最后一天
SELECT dateadd(ms,-3,DATEADD(mm, DATEDIFF(m,0,getdate())+1, 0))
h. 本月的第一个星期一
select DATEADD(wk, DATEDIFF(wk,0,
dateadd(dd,6-datepart(day,getdate()),getdate())
), 0)
i. 本年的最后一天
SELECT dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate())+1, 0))。
9.获取行号
mysql:
SELECT @rowno:=@rowno + 1 AS rowno,a.* FROM tableName a,(SELECT @rowno:=0) b
oracle:
SELECT rownum,a.* FROM tableName a

感谢那些网上提供相关SQL的作者

ElasticSearch 笔记 – 高级查询API

通用查询: match/multi_match
无论是全文搜索还是精确查询 它将用正确的分析器去分析查询字符串

范围查询: range

{
    "range": {
        "字段": {
            "gt":  20,
            "lt":   30
        }
    }
}

精确查询 term/terms

{ "term": { "age":    26 }}
term 查询对于输入的文本不分析 ,所以它将给定的值进行精确查询(包括在大小写、重音、空格等方面的差异)。

非空和空查询: exists/missing

{
    "exists":   {
        "field":    "字段"
    }
}
这与SQL中的 IS_NULL (missing) 和 NOT IS_NULL (exists) 在本质上具有共性

组合查询: bool

{
    "bool": {
        "must":     { "match": { "title": "how to make millions" }},
        "must_not": { "match": { "tag":   "spam" }},
        "should": [
            { "match": { "tag": "starred" }},
            { "range": { "date": { "gte": "2014-01-01" }}}
        ],
        "filter": {
          "range": { "date": { "lt": "2014-08-01" }} 
        }
    }
}
must
文档 必须 匹配这些条件才能被包含进来。
must_not
文档 必须不 匹配这些条件才能被包含进来。
should
如果满足这些语句中的任意语句,将增加 _score ,否则,无任何影响。它们主要用于修正每个文档的相关性得分。
filter
必须 匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档。

constant_score 查询

{
    "constant_score":   {
        "filter": {
            "term": { "category": "ebooks" } 
        }
    }
}
它被经常用于你只需要执行一个 filter 而没有其它查询(例如,评分查询)的情况下

查询分析: 在查询URL后加上explain

GET /_validate/query?explain
{
   "query": {
      "match" : {
         "tweet" : "really powerful"
      }
   }
}

如何选择查询与过滤编辑

通常的规则是,使用 查询(query)语句来进行 全文 搜索或者其它任何需要影响 相关性得分 的搜索。除此以外的情况都使用过滤(filters)。

ElasticSearch 笔记 – 基础API

#新增文档(可以指定id, 或者由es生成)
POST .kibana_1/_doc/[id]
{
  "visualization" : {
      "title" : "First ES Doc",
      "visState" : "this is my first es document2.",
      "uiStateJSON" : "{}",
    },
    "type" : "visualization",
    "updated_at" : "1556582400000"
}

#修改文档
PUT .kibana_1/_doc/466x1GoBzyYXTMCaEtuq
{
  "visualization" : {
      "title" : "First ES Doc",
      "visState" : "this is my first es document2.",
      "uiStateJSON" : "{}",
      "description" : "",
      "version" : 1,
      "kibanaSavedObjectMeta" : {
        "searchSourceJSON" : """{"query":{"query":"","language":"kuery"},"filter":[]}"""
      }
    },
    "type" : "visualization",
    "references" : [ ],
    "migrationVersion" : {
      "visualization" : "7.0.1"
    },
    "updated_at" : "1556582400000"
}

#id查找
GET .kibana_1/_doc/466x1GoBzyYXTMCaEtuq

#指定字段返回
GET .kibana_1/_doc/466x1GoBzyYXTMCaEtuq?_source=visualization.title,visualization.visState,type,migrationVersion

#分页查询size=多少, from从哪里开始
GET .kibana_1/_doc/_search?size=1&from=4000
{
  "query": {
    "match_all": {}
  }
}

#只返回内容
GET .kibana_1/_doc/466x1GoBzyYXTMCaEtuq/_source

#检查是否存在
HEAD .kibana_1/_doc/466x1GoBzyYXTMCaEtuq

#请求参数方式搜索
GET kibana_sample_data_ecommerce/_doc/_search?q=category:Men's Clothing+products.price:>700

#访问映射
GET kibana_sample_data_ecommerce/_mapping

# 分析器演示
GET /_analyze
{
  "analyzer": "english",
  "text": ["This is my house. i'm living here",
          "every one know that",
          "don't you know"]
}

#定义索引映射
PUT kibana_sample_data_ecommerce/_mapping
{
  "properties": {
      "category":{
        "type": "text",
        "index": true
      }
  }
}

#更新索引映射
es中想要给一个已经建好映射的索引改变映射结果,即使改变一个字段类型都是不支持的,
需要重新建立索引以及映射结构,然后把以前的数据导入到新建的索引结构中去,完成改变映射结构的目的。
步骤:
1.给已有的索引定一个别名,并指向该别名
2.新建一个新的索引,新的映射结构
3.将别名指向新的索引,取消旧的索引与别名之间的关联
通过这几部即可达到重新改变映射结构的内容,例如我们想改变library01的映射中price字段的类型由现有的double变为integer类型。

一个简单的例子:

#删除索引
DELETE products

#建立索引
PUT products
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1
  }
}
#建立映射
PUT products/_mapping
{
  "properties": {
    "category":{
      "type": "text",
      "index": true
    },
    "id":{
      "type": "text",
      "index": true
    },
    "name":{
      "type": "text",
      "analyzer": "standard"
    },
    "description":{
      "type": "text",
      "analyzer": "standard"
    },
    "price":{
      "type": "double"
    },
    "detail":{
      "type": "text",
      "analyzer": "standard"
    },
    "enabled":{
      "type": "boolean"
    },
    "picture":{
      "type": "text"
    }
  }
}
#查询映射
GET products/_mapping
#写入数据
POST /products/_doc
{
  "category": "HaiLan Home",
  "id": "A92934JSDFIQ9234SJDF",
  "name": "男裤",
  "description": "纯棉 男裤 夏季 清凉一夏 直筒",
  "price": 201.50,
  "enabled": true,
  "picture": "http://img.alicdn.com/tfscom/i4/1692495776/TB2vLAKaDMG5uJjSZFAXXbmspXa_%21%211692495776.jpg",
  "detail": "裤子是人们下体所穿的主要服饰。原写作“绔”、“袴”。从出土文物及传世文献来看,早在春秋时期,人们的下体己穿著裤,不过那时的裤子不分男女,都只有两只裤管,其形制和后世的套裤相似,无腰无裆,穿时套在胫上,即膝盖以下的小腿部分,所以这种裤子又被称为“胫衣”。左右各一,分衣两胫。因其只有两只裤管,所以裤的计数与鞋袜相同,都用“两”字来计,居延汉简中就有这样的情况。穿著这种裤子,其目的是为了遮护胫部,尤其在冬天,可以起到保暖的作用,至于膝盖以上部分则无遮护。"
}
#查询数据
GET products/_doc/_search

备注: 随着 7.0 版本的发布,type 的移除也是越来越近了,在 6.0 的时候,已经默认只能支持一个索引一个 type 了,7.0 版本新增了一个参数 include_type_name ,即让所有的 API 是 type 相关的,这个参数在 7.0 默认是 true,不过在 8.0 的时候,会默认改成 false,也就是不包含 type 信息了,这个是 type 用于移除的一个开关。 让我们看看最新的使用姿势吧,当 include_type_name 参数设置成 false 后:

 索引操作:
PUT {index}/{type}/{id}需要修改成PUT {index}/_doc/{id}
Mapping 操作:
PUT {index}/{type}/_mapping 则变成 PUT {index}/_mapping
所有增删改查搜索操作返回结果里面的关键字 _type 都将被移除, 父子关系使用 join 字段来构建

Linux下nohup日志输出过大问题解决方案

  1、nohup命令解释:

  a、语法:nohup [command] [args] [&]

  b、说明:nohup 命令运行由 Command 参数和任何相关的 Arg 参数指定的命令,忽略所有挂断信号。在注销后使用 nohup 命令运行后台中的程序。要运行后台中的 nohup 命令,添加 & ( 表示“and”的符号)到命令的尾部,如果不指定重定向,则日志默认输出到当前目录下nohup.out文件中,

  一般提交如 :nohup ./execute.sh &  这样日志或输出当前运行目下.nohup.out中

  重定向: nohup ./execute.sh >  /home/xxx/log.log 2>&1 & :这样日志会重定向到指定目录下
  0: 表示标准输入
  1: 标准输出,在一般使用时,默认的是标准输出
  2: 标准错误信息输出
     可以用来指定需要重定向的标准输入或输出。例如,将某个程序的错误信息输出到log文件中:./program 2>log。这样标准输出还是在屏幕上,但是错误信息会输出到log文件中。另外,也可以实现0,1,2之间的重定向。2>&1:将错误信息重定向到标准输出。
  关于/dev/null文件
  Linux下还有一个特殊的文件/dev/null,它就像一个无底洞,所有重定向到它的信息都会消失得无影无踪。这一点非常有用,当我们不需要回显程序的所有信息时,就可以将输出重定向到/dev/null。

2 、切分nohup.out,同时不让它无限增长

 我这里用的一般提交命令:nohup ./execute.sh &,这样在当前目录就有nohup.out文件了,这时候可以想办法定时将nohup.out切分成,多个小文件,但同时又要使nohup.out不会无限增长下去(一般情况下是程序不能中断的):

    a、每天(根据需要设置时间),定时切分前一天的日志,(比如每天大概1g,那么可以么次切分100m左右),

    b、切分完后将nohup.out文件情况,保证新的输出日志会不停的继续输出到nohup.out

  以上在shell中

  current_date=`date -d "-1 day" "+%Y%m%d"`

   split  -b 65535000 -d -a 4  nohup.out  ./log/log_${current_date}_   这里使用split命令,将nouhup文件按指定大小切分(65535000b 大概60多M吧,可以自定义大小 ),并分成指定格式(-d -a 4以4位数字形式为后缀以从0000开始,具体可以百度split命令用法),最终输出格式为log_20160610_0001

  cat /dev/null > nohup.out  (该命令会瞬间清空nohup.out文件,后续会继续写该文件),将日志定向到/dev/null中

使用重定向输出一样可以这样,只不过换成重定向的文件名即可

将这些命令定义在一个shell文件每天定时运行即可,这样每天日志会被分成若干份,排查也方便,而且如果日志积压过大的话。可以定时删除历史的日志,保留近几天即可

整体代码如下:

this_path=$(cd `dirname $0`;pwd)

cd $this_path
echo $this_path
current_date=`date -d "-1 day" "+%Y%m%d"`
echo $current_date
split -b 65535000 -d -a 4 /home/.../nohup.out   /home/.../log/log_${current_date}_

cat /dev/null > nohup.out

https://blog.csdn.net/shawnhu007/article/details/50971084

Kafka 监控

KafkaOffsetMonitor托管在Github上,可以通过Github下载。
下载地址:https://github.com/quantifind/KafkaOffsetMonitor/releases

启动命令:

java -cp KafkaOffsetMonitor-assembly-0.2.1.jar com.quantifind.kafka.offsetapp.OffsetGetterWeb --zk 127.0.0.1:2181,127.0.0.1:2182 --port 6088  --refresh 5.seconds --retain 1.days
参数说明:

zk :zookeeper主机地址,如果有多个,用逗号隔开
port :应用程序端口
refresh :应用程序在数据库中刷新和存储点的频率
retain :在db中保留多长时间
dbName :保存的数据库文件名,默认为offsetapp
或者写一个shell脚本:
nohup java -Xms512M -Xmx512M -Xss1024K -XX:PermSize=256m -XX:MaxPermSize=512m  -cp KafkaOffsetMonitor-assembly-0.2.0.jar com.quantifind.kafka.offsetapp.OffsetGetterWeb \
--port 6088 \
--zk 127.0.0.1:2181,127.0.0.1:2182 \
--refresh 5.minutes \
--retain 1.day >/dev/null 2>&1 &

启动好后, 在浏览器中就能看见 Group, Topic, Consumer 等信息

备注: Kafka有一个坑,默认情况下Producer往一个不存在的Topic发送message时会自动创建这个Topic。 如果同时传递message和topic时, 传入的参数反了,将会在Kafka集群中自动创建Topic。在正常情况下,应该是先把Topic根据需要创建好,然后Producer往该Topic发送Message,最好把Kafka这个默认自动创建Topic的功能关掉。 
  那么,假设真的不小心创建了多余的Topic,在删除时,会出现“marked for deletion”提示,只是将该topic标记为删除,使用list命令仍然能看到。如果需要调整这两个功能的话,在server.properties中配置如下两个参数:

参数 默认值 作用
auto.create.topics.enable true Enable auto creation of topic on the server
delete.topic.enable false Enables delete topic. Delete topic through
the admin tool will have no effect
if this config is turned off

kafkaOffsetMonitor:程序一个jar包的形式运行,部署较为方便。只有监控功能,使用起来也较为安全。
除了KafkaOffsetMonitor,Kafka监控工具还有另外两款:
Kafka Web Console:监控功能较为全面,可以预览消息,监控Offset、Lag等信息,但存在bug,不建议在生产环境中使用。
Kafka Manager:偏向Kafka集群管理,若操作不当,容易导致集群出现故障。对Kafka实时生产和消费消息是通过JMX实现的。没有记录Offset、Lag等信息。

linux 添加自签名证书/Nginx 配置Https

自签名证书做法

1.先生成一对秘钥,把公钥做成证书 server.key

openssl  genrsa [-des3] -out server.key 2048       生成一个 2048 位的 私钥

说明:生成rsa私钥,des3算法,2048位强度,server.key是秘钥文件名。
注意:生成私钥,需要提供一个至少4位的密码, 如果不需要, 直接去掉-des3选项
这个密码会带来一个副作用,那就是在每次Apache启动Web服务器时,都会要求输入密码,这显然非常不方便。要删除私钥中的密码,操作如下:
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key

我们可以 输出它的公钥看看

openssl  rsa -in server.key -pubout

2. 生成跟CA并自签(证书签名请求)

生成私钥之后,便可以创建csr文件了。
此时可以有两种选择。理想情况下,可以将证书发送给证书颁发机构(CA),CA验证过请求者的身份之后,会出具签名证书(很贵)。另外,如果只是内部或者测试需求,也可以使用OpenSSL实现自签名,具体操作如下:

openssl req -new -x509 -key server.key -out server.csr
国家 Country Name:  CN   
省    Stat or Province Name   Shanghai
市   Locality Name     Shanghai
公司  Organization Name :  HUPU
部门 Organizational Unit   Tech
主机名 Common Name    www.zmz8.com
邮件  Email Address    279861795@qq.com

3.生成证书CRT server.crt

openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
备注: crt 转 p12
openssl x509 -in server.crt -inform der -out server.pem
openssl pkcs12 -export -inkey server.key-in server.pem -out server.p12

我们可以查看证书内容

openssl  x509  -text -in server.crt

4.配置nginx

证书路径 /usr/local/nginx/ssl/server.crt

私钥路径 /usr/local/nginx/ssl/server.key

nginx添加配置
server {
    listen 80;
    server_name     www.zmz8.com;
    #rewrite ^/(.*)$ https://www.zmz8.com/$1 permanent;
    return 307 https://$host$request_uri;
}
server {
  listen 443;
  server_name  www.zmz8.com;
  ssl on;
  ssl_certificate   ../ssl/server.crt;
  ssl_certificate_key  ../ssl/server.key;
  ssl_session_timeout 5m;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
}

最后如果可以的话 ,可以配置一个服务器签署

openssl req -new -out server.csr -key server.key -config /etc/pki/tls/openssl.cnf 
OpenSSL工具说明:
OpenSSL   ssl的开源实现,几乎实现了市面上所有的加密
libcrypto: 通用加密库, 任何软件要实现加密功能 链接调用这个库
libssl:   TLS/SSL 加密库  
openssl: 命令行工具   多功能多用途工具  实现私有证书颁发机构
子命令:
genrsa    [-out filename]    [-passout arg] [numbits]
generate an  RSA  private key  
生成一个 RSA 的私钥 (公钥是从私钥中提取的,有了私钥 就有公钥)
openssl  rsa -in ca.key -pubout  提取私钥
创建证书的基本流程是这样:
生成自己的服务端私钥     Server Key
输入基本信息并用私钥签名生成CSR    证书签名请求
提交CSR给证书机构CA(免费或商业证书)签名生成CRT,或自己做CA签名生成CRT(自签名证书)
生成RSA服务器私钥:
openssl genrsa -out server.key 4096 
输出的server.key文件就是服务器私钥,4096是密钥长度,要求不高的话用2048也可。
生成CSR:
执行命令  openssl req -new -nodes -sha256 -newkey rsa:2048 -keyout myprivate.key -out mydomain.csr生成 CSR 文件。
其中,
-new 指定生成一个新的CSR。
-nodes 指定私钥文件不被加密。
-sha256 指定摘要算法。
-keyout 生成私钥文件。
-newkey rsa:2048 指定私钥类型和长度。 
因为sha1已经不安全,所以这里用了sha256,可能太旧的客户端(比如win98?)会不支持。
yoursite.csr就是生成的CSR,yoursite建议用你的网站名标识会比较方便识别。
然后按提示输入:
国家
省
市
公司
部门
通用名(即网站域名,这个必须准确,有些商业证书支持在这里用带www的域名后签发出同时支持不带www的域名)
email
密码(可选,设置的话以后重启webserver都需要输入密码)

参考连接:

https://www.jianshu.com/p/44a3efae1d84

https://blog.csdn.net/yongf_xu/article/details/85006854

Maven和Findbugs集成

1.配置pom.xml

<build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>findbugs-maven-plugin</artifactId>
                <version>3.0.4</version>
                <configuration>
                    <!--配置文件-->
                    <configLocation>${basedir}/findbugs-config.xml</configLocation>
                    <!--排除的BUG规则-->
                    <excludeFilterFile>custom-findbugs-exclude.xml</excludeFilterFile>
                    <!--包含的BUG规则-->
                    <includeFilterFile>custom-findbugs-include.xml</includeFilterFile>
                    <!--检查等级-->
                    <threshold>High</threshold>
                    <effort>Default</effort>
                    <!-- 输出配置 -->
                    <findbugsXmlWithMessages>true</findbugsXmlWithMessages>
                    <findbugsXmlOutput>true</findbugsXmlOutput>
                    <xmlOutput>true</xmlOutput>
                    <findbugsXmlOutputDirectory>target/site</findbugsXmlOutputDirectory>
                </configuration>
            </plugin>
        </plugins>
    </build>

custom-findbugs-exclude.xml内容:

<FindBugsFilter>
    <Match>
        <Bug pattern="DLS_DEAD_LOCAL_STORE"/>
    </Match>

    <Match>
        <Bug pattern="DM_BOXED_PRIMITIVE_FOR_PARSING"/>
    </Match>

    <Match>
        <Bug pattern="EI_EXPOSE_REP"/>
    </Match>

    <Match>
        <Bug pattern="EI_EXPOSE_REP2"/>
    </Match>

    <Match>
        <Bug pattern="ME_ENUM_FIELD_SETTER"/>
    </Match>
</FindBugsFilter>

2. 运行findbugs任务(先运行“mvn package”编译工程 )

mvn findbugs:help      
查看findbugs插件的帮助  
mvn findbugs:check      
检查代码是否通过findbugs检查,如果没有通过检查,检查会失败,但检查不会生成结果报表  
mvn findbugs:findbugs   
检查代码是否通过findbugs检查,如果没有通过检查,检查不会失败,会生成结果报表保存在target/findbugsXml.xml文件中  
mvn findbugs:gui        
检查代码并启动gui界面来查看结果  

具体fndbugs插件的配置项可以参考http://mojo.codehaus.org/findbugs-maven-plugin/findbugs-mojo.html

WordPress 搭建

  1. 环境准备 – 数据库(mariadb)

参考:https://www.cnblogs.com/river2005/p/6813618.html
CentOS7下使用yum安装MariaDB
CentOS 6 或早期的版本中提供的是 MySQL 的服务器/客户端安装包,但 CentOS 7 已使用了 MariaDB 替代了默认的 MySQL。MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。

Linux下安装MariaDB官方文档参见:https://mariadb.com/kb/zh-cn/installing-mariadb-with-yum/

全部删除MySQL/MariaDBMySQL 已经不再包含在 CentOS 7 的源中,而改用了 MariaDB;

 1.使用rpm -qa | grep mariadb搜索 MariaDB 现有的包: 
如果存在,使用rpm -e --nodeps mariadb-*全部删除:
[root@localhost ~]# rpm -qa | grep mariadb
[root@localhost ~]# rpm -e mysql-*

2.使用rpm -qa | grep mariadb搜索 MariaDB 现有的包:
如果存在,使用yum remove mysql mysql-server mysql-libs compat-mysql51全部删除;
[root@localhost ~]# yum remove mysql mysql-server mysql-libs compat-mysql51

3.开始新的安装, 创建MariaDB.repo文件
vi /etc/yum.repos.d/MariaDB.repo
插入以下内容:
# MariaDB 10.2.4 CentOS repository list - created 2017-05-05 16:13 UTC
# http://downloads.mariadb.org/mariadb/repositories/
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.2.4/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1

4.运行安装命令安装MariaDB
[root@localhost ~]# yum -y install MariaDB-server MariaDB-client

5. 安装成功之后启动MariaDB服务。
systemctl start mariadb #启动服务 systemctl enable mariadb #设置开机启动 systemctl restart mariadb #重新启动 systemctl stop mariadb.service #停止MariaDB

6. 进行MariaDB的相关简单配置,使用mysql_secure_installation命令进行配置。

7.配置MariaDB的字符集
  查看/etc/my.cnf文件内容,其中包含一句!includedir /etc/my.cnf.d 说明在该配置文件中引入/etc/my.cnf.d 目录下的配置文件。
  
1)使用vi server.cnf命令编辑server.cnf文件,在[mysqld]标签下添加
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
如果/etc/my.cnf.d 目录下无server.cnf文件,则直接在/etc/my.cnf文件的[mysqld]标签下添加以上内容。
2)文件/etc/my.cnf.d/client.cnf
vi /etc/my.cnf.d/client.cnf
在[client]中添加
default-character-set=utf8
3)文件/etc/my.cnf.d/mysql-clients.cnf
vi /etc/my.cnf.d/mysql-clients.cnf
在[mysql]中添加
default-character-set=utf8
 全部配置完成,重启mariadb
systemctl restart mariadb
之后进入MariaDB查看字符集
mysql> show variables like "%character%";show variables like "%collation%";
授予权限并且可以授权
mysql>grant all privileges on *.* to username@'hostname' identified by 'password' with grant option;

2. 环境准备 – php

1、由于linux的yum源不存在php7.x,所以我们要更改yum源:
rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
 2、yum查询安装php71w
yum search php71w
3、yum 安装php71w和各种拓展,选自己需要的即可。
yum install php71w php71w-cli php71w-common php71w-devel php71w-embedded php71w-fpm php71w-gd php71w-mbstring php71w-mysqlnd php71w-opcache php71w-pdo php71w-xml

php -v //就可以看到PHP版本信息了。
4. 修改配置文件
编辑PHP的配置文件,/etc/php.ini,注意去掉分号注释
vim /etc/php.ini
  将 ;cgi.fix_pathinfo=1 改为 cgi.fix_pathinfo=0
编辑PHP-FPM配置文件
vim /etc/php-fpm.d/www.conf
  将
  user = nobody
  group = nobody   
 改为
  user = nginx
  group = nginx
 前提是已经创建了nginx用户和nginx组。如果没有创建方法:
groupadd -r nginx
useradd -r -g nginx nginx
5、启动PHP—FPM
systemctl start php-fpm
6、设置开机启动
systemctl enable php-fpm
7,确保Nginx配置文件修该之后,重启Nginx
systemctl restart nginx
8、在/usr/share/nginx/html/目录下创建info.php
    内容如下:
   <?php phpinfo();?>
然后在浏览器访问这个文件, 看看是否成功

3. 环境准备 – nginx

安装nginx
yum install nginx
修改nginx 配置
vim /etc/nginx/nginx.conf
去掉默认的server配置
在/etc/ngnix/conf.d/下,新增一个配置文件wordpress.conf
内容为:

server {
listen 80 default;
server_name blog.javastone.net blog.caul.com.cn;
index index.php index.html index.htm index.jsp;
root /usr/local/wordpress;
error_page 404 /404.html; location = /40x.html { }
  error_page 500 502 503 504 /50x.html; location = /50x.html { }
  location ~ \.php$ {
  try_files $uri =404;
  fastcgi_pass 127.0.0.1:9000;
  fastcgi_index index.php;
  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  include fastcgi_params; 
  }
  location / {
  index index.php;
  }
  access_log /data/logs/nginx/blog.log;
}

4. 部署

参考官方文档, 主要是修改配置文件wp-config.php

/** WordPress数据库的名称 */
define('DB_NAME', '数据库');
/** MySQL数据库用户名 */
define('DB_USER', '用户');
/** MySQL数据库密码 */
define('DB_PASSWORD', '密码');
/** MySQL主机 */
define('DB_HOST', '主机IP');

去https://api.wordpress.org/secret-key/1.1/salt/ 拿到一个key,
替换define中的AUTH_KEY等信息
define('AUTH_KEY', '');
define('SECURE_AUTH_KEY', '');
define('LOGGED_IN_KEY', '');
define('NONCE_KEY', '\');
define('AUTH_SALT', '');
define('SECURE_AUTH_SALT', '');
define('LOGGED_IN_SALT', '');
define('NONCE_SALT', '');*/
define('AUTH_KEY', '');
define('SECURE_AUTH_KEY', '');
define('LOGGED_IN_KEY', '');
define('NONCE_KEY', '\');
define('AUTH_SALT', '');
define('SECURE_AUTH_SALT', '');
define('LOGGED_IN_SALT', '');
define('NONCE_SALT', '');