
暂无个人介绍
能力说明:
基本的计算机知识与操作能力,具备Web基础知识,掌握Web的常见标准、常用浏览器的不同特性,掌握HTML与CSS的入门知识,可进行静态网页的制作与发布。
阿里云技能认证
详细说明一. 问题描述 执行如下命令后会安装图形界面,但是重启后无法进入,卡在登录界面 sudo apt install ubuntu-desktop && sudo startx 二. 原因 电脑配置了GPU, 而Ubuntu默认没有这个驱动,导致卡死。 三. 解决方案 1. 删除已有的nvidia驱动 sudo apt-get purge nvidia-* 2. 安装nvidia驱动并chon重启 sudo apt install software-properties-common sudo add-apt-repository ppa:graphics-drivers/ppa sudo apt-get update sudo apt-get install nvidia-384 sudo reboot 其中384代表nvidia版本, 如想使用其他版本, 可以到nvidia官网查看版本号 3. 验证是否安装成功 nvidia-smi 如果看到nvidia相关信息则说明安装成功
一. Ubuntu 安装JDK的两种方式 1. 通过apt安装. 2. 通过官网下载安装包安装. 这里推荐第1种,因为可以通过 apt-get upgrade 方式方便获得jdk的升级 二. 通过apt安装(jdk有很多版本, 这里介绍两种: openjdk和oracle的JDK) 1. openjdk (1) 查找合适的openjdk版本: apt-cache search openjdk 输入以上命令后会列出很多版本, 选择自己需要的即可: default-jdk-doc - Standard Java or Java compatible Development Kit (documentation) …(省略部分显示结果) openjdk-6-source - OpenJDK Development Kit (JDK) source files openjdk-7-jre-dcevm - Alternative VM for OpenJDK 7 with enhanced class redefinition openjdk-7-jre-lib - OpenJDK Java runtime (architecture independent libraries) openjdk-7-jre-zero - Alternative JVM for OpenJDK, using Zero/Shark openjdk-8-dbg - Java runtime based on OpenJDK (debugging symbols) openjdk-8-demo - Java runtime based on OpenJDK (demos and examples) openjdk-8-doc - OpenJDK Development Kit (JDK) documentation openjdk-8-jdk - OpenJDK Development Kit (JDK) openjdk-8-jre - OpenJDK Java runtime, using Hotspot JIT openjdk-8-jre-headless - OpenJDK Java runtime, using Hotspot JIT (headless) openjdk-8-jre-jamvm - Alternative JVM for OpenJDK, using JamVM openjdk-8-jre-zero - Alternative JVM for OpenJDK, using Zero/Shark openjdk-8-source - OpenJDK Development Kit (JDK) source files uwsgi-app-integration-plugins - plugins for integration of uWSGI and application uwsgi-plugin-jvm-openjdk-7 - Java plugin for uWSGI (OpenJDK 7) (2) 安装 sudo apt-get install openjdk-8-jdk (3) 配置环境变量, 编辑如下文件: vim ~/.bashrc 在最后一行加: export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export PATH=$JAVA_HOME/bin:$PATH export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar (4) 测试jdk是否安装成功: java -version 显示如下结果, 则说明安装成功: openjdk version “1.8.0_91” OpenJDK Runtime Environment (build 1.8.0_91-8u91-b14-0ubuntu4~15.10.1-b14) OpenJDK Server VM (build 25.91-b14, mixed mode) 2. oracle的JDK (1) 添加ppa sudo apt install software-properties-common sudo add-apt-repository ppa:webupd8team/java sudo apt-get update (2) 安装oracle-java-installer sudo apt-get install oracle-java8-installer 安装器会提示你同意 oracle 的服务条款,选择 ok, 然后选择yes 即可 (3) 设置系统默认jdk sudo update-java-alternatives -s java-8-oracle (4) 如果即安装了jdk7,又安装了jdk8,要实现两者的切换,可以:jdk8 切换到jdk7 sudo update-java-alternatives -s java-7-oracle jdk7 切换到jdk8 sudo update-java-alternatives -s java-8-oracle (5) 测试jdk是否安装成功: java -version 三. 直接下载jdk压缩包方式安装 1. 官网下载JDK 地址: http://www.oracle.com/technetwork/articles/javase/index-jsp-138363.html, 选择相应的 .gz包下载 2. 解压缩,放到指定目录(以jdk-7u60-linux-x64.gz为例) 创建目录: sudo mkdir /usr/lib/jvm 解压缩到该目录: sudo tar -zxvf jdk-7u60-linux-x64.gz -C /usr/lib/jvm 3. 修改环境变量 sudo vim ~/.bashrc 文件的末尾追加下面内容: #set oracle jdk environment export JAVA_HOME=/usr/lib/jvm/jdk1.7.0_60 ## 这里要注意目录要换成自己解压的jdk 目录 export JRE_HOME=${JAVA_HOME}/jre export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib export PATH=${JAVA_HOME}/bin:$PATH 使环境变量马上生效: source ~/.bashrc 4. 设置系统默认jdk版本 sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk1.7.0_60/bin/java 300 sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/jdk1.7.0_60/bin/javac 300 sudo update-alternatives --install /usr/bin/jar jar /usr/lib/jvm/jdk1.7.0_60/bin/jar 300 sudo update-alternatives --install /usr/bin/javah javah /usr/lib/jvm/jdk1.7.0_60/bin/javah 300 sudo update-alternatives --install /usr/bin/javap javap /usr/lib/jvm/jdk1.7.0_60/bin/javap 300 然后执行: sudo update-alternatives --config java 若是初次安装jdk,会有下面的提示 : There is only one alternative in link group java (providing /usr/bin/java): /usr/lib/jvm/jdk1.7.0_60/bin/java 5. 测试jdk java -version 若有如下结果, 则说明jdk 安装成功: java version "1.7.0_60" Java(TM) SE Runtime Environment (build 1.7.0_60-b19) Java HotSpot(TM) 64-Bit Server VM (build 24.60-b09, mixed mode) 6. 可能出现的错误信息 bash: ./java: cannot execute binary file 出现这个错误的原因可能是在32位的操作系统上安装了64位的jdk, 查看你安装的Ubuntu是32位还是64位系统: sudo uname -m i686表示是32位, x86_64表示是64位
一. VMware12安装VMwareTool 1. 在CD-ROM虚拟光驱中选择使用ISO镜像, 找到VMWARE TOOLS 安装文件 如C:/VMware/VMware Workstation/Programs/linux.iso 当然这个ISO是你安装VMware workstation 的目录下的Linux.iso, 不是你的Linux OS 镜像文件. VMware Tools一般都在这个文件里. 2. 以管理员身份进入Linux, root账号 3. 退出到windows, 在虚拟机菜单栏中点击 虚拟机-> 安装 VMWARE TOOLS 子菜单,会弹出对话框, 点击"确认" 安装 4. 挂载光驱 mount -t iso9660 /dev/cdrom /mnt 5. copy 此文件到临时文件夹 cp /mnt/mVMwareTools-8.8.4-743747.tar.gz /tmp 6. 卸载CDROM umount /dev/cdrom 7. 解压安装包 tar -zxvf /tmp/mVMwareTools-8.8.4-743747.tar.gz 8. 进入解压后的文件夹, 运行vmware-install.pl文件进行安装 (1) 安装过程中他会一步一步的有问题回应, 此过程中, 你遇到显示[yes],[no],yes的直接输入yes, 然后回车. 其他的问题不管[]里面是什么, 直接回车就好了, 不要输入. (2) 安装过程遇到如下提问: what is the location of the gcc program on your machine?不用输入, 直接回车, 然后输入no, 先跳过gcc的安装. 等安装完VMwareTool后, 执行如下命令, 一顿yes即可. yum install gcc-c++ 二. RedHat7安装MySQL5.7.19 1. 自定义目录说明 (1)MySQL安装目录: /usr/local/mysql (2)数据库目录: /data/mysql (3)日志保存目录: /data/log/mysql 2. 下载路径 https://downloads.mysql.com/archives/community/ 3. 解压并复制到/usr/local/mysql tar -zxvf mysql-5.7.19-linux-glibc2.12-x86_64.tar.gz mv mysql-5.7.19-linux-glibc2.12-x86_64 /usr/local/mysql 4. 创建数据库目录/data/mysql mkdir /data mkdir /data/mysql 5. 创建MySQL组, 用户, 并禁止用户登录shell useradd -r -s /sbin/nologin -g mysql mysql -d /usr/local/mysql 6. 更改文件夹权限 chown –R mysql /usr/local/mysql chgrp –R mysql /usr/local/mysql chown -R mysql /data chmod -R 755 /data chown -R mysql /data/mysql 7. 修改/etc/my.cnf文件 [client] port=3306 socket=/tmp/mysql.sock [mysql] default-character-set=utf8 [mysqld] lower_case_table_names=1 default-storage-engine=INNODB character_set_server=utf8 port=3306 socket=/tmp/mysql.sock basedir=/usr/local/mysql datadir=/data/mysql tmpdir=/tmp pid-file=/data/mysql/mysql.pid user=mysql bind-address=0.0.0.0 explicit_defaults_for_timestamp=true [mysqld_safe] open-files-limit=65535 log-error=/data/log/mysql/mysql_error.log log=/data/log/mysql/mysql.log 8. 初始化MySQL /usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql --pid-file=/data/mysql/mysql.pid --tmpdir=/tmp 记录上述语句生成的临时密码, 并执行如下语句 /usr/local/mysql/bin/mysql_ssl_rsa_setup --datadir=/data/mysql 9. 修改系统配置参数 cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql vim /etc/init.d/mysql 在打开的文件中, 找到并修改如下代码 basedir=/usr/local/mysql datadir=/data/mysql 10. 创建MySQL日志文件 mkdir /data/log mkdir /data/log/mysql touch /data/log/mysql/mysql.log touch /data/log/mysql/mysql_error.log 11. 创建MySQL的PID文件 touch /data/mysql/mysql.pid 12. 创建MySQL命令的软链接 ln –s /usr/local/mysql/bin/mysql /usr/bin ln –s /usr/local/mysql/bin/mysqladmin /usr/bin 13. 启动MySQL服务 service mysql start 14. 进入MySQL mysql –u root –p 输入第8步中记录的临时密码 15. 修改密码 mysql> set password=password('myNewPassword') mysql> exit 三. Ubuntu16.04上安装并启动Nginx 1. 通过apt命令安装 sudo apt update sudo apt install nginx 2. 配置防火墙 (1) 显示所有ufw应用的配置 sudo ufw app list # 得到一个配置的输出列表: Available applications: Nginx Full Nginx HTTP Nginx HTTPS OpenSSH 有三个Nginx的配置: Nginx Full: 这个配置打开 80端口和443端口 Nginx HTTP: 这个配置只打开80 (普通, 未加密通信) Nginx HTTPS: 这个配置只打开 443 (TLS/SSL 加密通信 ) (2) 打开80端口 sudo ufw allow 'Nginx HTTP' 验证修改状态: (若未启动ufw, 可使用命令: sudo ufw enable) sudo ufw status # 我们可以看到HTTP是被打开的: Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere Nginx HTTP ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) Nginx HTTP (v6) ALLOW Anywhere (v6) 3. 启动Nginx nginx 如果敲地址后看到如下欢迎页面, 则说明Nginx启动成功停止Nginx: nginx -s stop 4. 也可以使用systemctl控制Nginx (1) 启动Nginx: sudo systemctl start nginx (2) 停止Nginx: sudo systemctl stop nginx (3) 重启Nginx: sudo systemctl restart nginx (4) 修改配置文件后, 平滑加载配置命令(不会断开用户访问): sudo systemctl reload nginx (5) Nginx默认是随着系统启动的时候自动运行, 如果你不想开机启动, 那么你可以禁止Nginx开机启动: sudo systemctl disable nginx (6) 重新配置Nginx开机自动启动: sudo systemctl enable nginx
一. 可以使用如下命令查看文件夹的目录结构 sudo tree /etc/nginx 二. 网站文件 /var/www/html为网站文件存放的地方, 默认只有Nginx欢迎页面, 可以通过改变Nginx配置文件的方式来修改这个位置. 三. 服务器配置文件 1. /etc/nginx Nginx配置文件目录, 所有的Nginx配置文件都在这里. 2. /etc/nginx/nginx.conf Nginx的主配置文件, 可以修改它来改变Nginx的全局配置. 3. /etc/nginx/sites-available 这个目录存储每一个网站的"server blocks", Nginx通常不会使用这些配置, 除非它们被链接到sites-enabled目录. 一般所有的server block配置都在这个目录中设置, 然后软链接到别的目录. 4. /etc/nginx/sites-enabled 这个目录存储生效的"server blocks"配置. 通常, 这个配置都是链接到sites-available目录中的配置文件. 5. /etc/nginx/snippets 这个目录主要可以包含在其它Nginx配置文件中的配置片段, 重复的配置都可以重构为配置片段. 四. 日志文件 1. /var/log/nginx/access.log 每一个访问请求都会默认记录在这个文件中, 除非你做了其它设置. 2. /var/log/nginx/error.log 任何Nginx的错误信息都会记录到这个文件中.
1. 通用命令: 查看防火墙版本 iptables -version 2. RHEL6 (1) 查看防火墙状态(如果得到一系列的信息, 说明防火墙处于开启状态) /etc/init.d/iptables status (2) 开启/关闭防火墙, 重启后生效 chkconfig iptables on chkconfig iptables off (3) 开启/关闭/重启防火墙, 即时生效, 但重启系统后防火墙会恢复到之前的开启或关闭状态 service iptables stop service iptables start service iptables restart (4) 允许访问80端口 iptables -I INPUT -i eth0 -p tcp --dport 80 -j ACCEPT iptables -I OUTPUT -o eth0 -p tcp --sport 80 -j ACCEPT /etc/rc.d/init.d/iptables save (5) 阻止访问80端口 iptables -I INPUT -i eth0 -p tcp --dport 80 -j DROP iptables -I OUTPUT -o eth0 -p tcp --sport 80 -j DROP /etc/rc.d/init.d/iptables save 3. RHEL7 (1) 启动/关闭防火墙服务 systemctl start firewalld.service systemctl stop firewalld.service systemctl restart firewalld.service (2) 显示防火墙服务状态 systemctl status firewalld.service (3) 设置开机启动/禁用防护墙服务 systemctl enable firewalld.service systemctl disable firewalld.service (4) 查看防火墙服务是否开机启动 systemctl is-enabled firewalld.service;echo $? (5) 查看已启动的服务列表 systemctl list-unit-files | grep enabled (6) 查看防火墙允许的端口号 firewall-cmd --zone=public --list-ports (7) 允许访问80端 sudo firewall-cmd --zone=public --add-port=80/tcp --permanent sudo firewall-cmd --reload 若不使用“--permanent”, 则防火墙规则在重启后会失效. (8) 阻止访问80端口 sudo firewall-cmd --zone=public --remove-port=80/tcp --permanent sudo firewall-cmd --reload 若不使用“--permanent”, 则防火墙规则在重启后会失效. 4. Ubuntu (1) 由于Linux原始的防火墙工具iptables过于繁琐, 所以Ubuntu默认提供了一个基于iptable之上的防火墙工具ufw. Ubuntu已默认安装ufw. (2) 安装防火墙 apt install ufw (3) 查看版本 ufw version (4) 打开/关闭防火墙 ufw enable ufw disable (5) 外来访问默认允许/拒绝 ufw default allow/deny (6) 显示防火墙状态 ufw status (7) 允许/禁用某服务对应的端口号(ufw从/etc/services中找到对应service的端口, 进行过滤) sudo ufw allow [service] sudo ufw deny [service] 例如: sudo ufw allow ssh表明: 允许所有的外部IP访问本机的22/tcp(ssh)端口 (8) 允许/禁用某端口号(例: 22包括tcp和udp, 22/tcp只是tcp端口, 22/udp只是udp端口) sudo ufw allow 22 sudo ufw deny 22 (9) 允许/禁用某特定IP ufw allow from 122.168.254.254 to any ufw deny from 122.168.254.254 to any (10) 允许/禁用某特定IP的某个端口的访问 ufw allow from 122.168.254.254 to any port 80 ufw deny from 122.168.254.254 to any port 80 (11) 删除某个已定义的规则 <1> 显示规则号, 输入如下命令 sudo ufw status numbered # 会显示防火墙的已有规则并编号 Status: active To Action From -- ------ ---- [ 1] Nginx HTTP ALLOW IN Anywhere [ 2] OpenSSH ALLOW IN Anywhere [ 3] Nginx HTTP (v6) ALLOW IN Anywhere (v6) [ 4] OpenSSH (v6) ALLOW IN Anywhere (v6) <2> 根据编号删除某个规则, 如删除上面Nginx(v6)的规则 sudo ufw delete 3 (12) /var/lib/ufw/user.rules这个文件中是我们设置的一些防火墙规则, 有时我们可以直接修改这个文件, 不用使用命令来设定. 修改后记得ufw reload后重启ufw使得新规则生效.
1. 查看无线网卡的信息 iwconfig 输入类似如下结果 rmnetctl no wireless extensions. wlan0 IEEE 802.11abgn ESSID:off/any Mode:Managed Access Point: Not-Associated Tx-Power=31 dBm Retry long limit:7 RTS thr:off Fragment thr:off Power Management:on dummy0 no wireless extensions. enx00044b6697cd no wireless extensions. ip6tnl0 no wireless extensions. sit0 no wireless extensions. lo no wireless extensions. tunl0 no wireless extensions. 注意: 需要在你的无线网卡存在, 且无线网卡驱动安装后, 才会检测到类似上面的wlan0的网卡项. 如果没有网卡项, 请先确认您的机子上存在无线网卡, 且驱动正确安装. 2. 启动无线网卡项 sudo ip link set wlan0 up 3. 扫描所检测到的无线网络 sudo iw dev wlan0 scan | less 输出如下 BSS f0:b4:29:61:92:ef(on wlan0) TSF: 9516218618 usec (0d, 02:38:36) freq: 2447 beacon interval: 100 TUs capability: ESS Privacy ShortSlotTime APSD (0x0c11) signal: -58.00 dBm last seen: 10 ms ago Information elements from Probe Response frame: SSID: Xiaomi_517 Supported rates: 1.0* 2.0* 5.5* 11.0* 9.0 18.0 36.0 54.0 DS Parameter set: channel 8 ERP: Barker_Preamble_Mode Extended supported rates: 6.0 12.0 24.0 48.0 HT capabilities: Capabilities: 0x6c HT20 SM Power Save disabled RX HT20 SGI RX HT40 SGI No RX STBC Max AMSDU length: 3839 bytes No DSSS/CCK HT40 Maximum RX AMPDU length 65535 bytes (exponent: 0x003) Minimum RX AMPDU time spacing: 4 usec (0x05) HT RX MCS rate indexes supported: 0-15 HT TX MCS rate indexes are undefined HT operation: * primary channel: 8 * secondary channel offset: no secondary * STA channel width: 20 MHz * RIFS: 0 * HT protection: no * non-GF present: 0 * OBSS non-GF present: 0 * dual beacon: 0 * dual CTS protection: 0 * STBC beacon: 0 * L-SIG TXOP Prot: 0 * PCO active: 0 * PCO phase: 0 WPA: * Version: 1 * Group cipher: TKIP * Pairwise ciphers: TKIP CCMP * Authentication suites: PSK RSN: * Version: 1 * Group cipher: TKIP * Pairwise ciphers: TKIP CCMP * Authentication suites: PSK * Capabilities: 1-PTKSA-RC 1-GTKSA-RC (0x0000) WMM: * Parameter version 1 * u-APSD * BE: CW 15-1023, AIFSN 3 * BK: CW 15-1023, AIFSN 7 * VI: CW 7-15, AIFSN 2, TXOP 3008 usec * VO: CW 3-7, AIFSN 2, TXOP 1504 usec BSS Load: * station count: 0 * channel utilisation: 19/255 * available admission capacity: 31250 [*32us] Country: CN Environment: Indoor/Outdoor Channels [1 - 13] @ 16 dBm WPS: * Version: 1.0 * Wi-Fi Protected Setup State: 2 (Configured) * Response Type: 3 (AP) * UUID: 28802880-2880-1880-a880-f0b4296192ef * Manufacturer: xiaomi * Model: R1CM * Model Number: 0002 * Serial Number: 12345678 * Primary Device Type: 6-0050f204-1 * Device name: XiaoMiRouter * Config methods: Label, Display, Keypad * RF Bands: 0x1 * Unknown TLV (0x1049, 6 bytes): 00 37 2a 00 01 20 BSS b0:c5:54:81:0d:aa(on wlan0) TSF: 9516218240 usec (0d, 02:38:36) freq: 2412 beacon interval: 100 TUs capability: ESS Privacy ShortPreamble ShortSlotTime (0x0431) signal: -65.00 dBm last seen: 10 ms ago Information elements from Probe Response frame: SSID: CSR Supported rates: 1.0* 2.0* 5.5* 11.0* 6.0 9.0 12.0 18.0 DS Parameter set: channel 1 ERP: <no flags> Extended supported rates: 24.0 36.0 48.0 54.0 HT capabilities: Capabilities: 0x186e HT20/HT40 SM Power Save disabled RX HT20 SGI RX HT40 SGI No RX STBC Max AMSDU length: 7935 bytes DSSS/CCK HT40 Maximum RX AMPDU length 32767 bytes (exponent: 0x002) Minimum RX AMPDU time spacing: 16 usec (0x07) HT RX MCS rate indexes supported: 0-15 HT TX MCS rate indexes are undefined HT operation: * primary channel: 1 * secondary channel offset: above * STA channel width: any * RIFS: 0 * HT protection: nonmember * non-GF present: 0 * OBSS non-GF present: 1 * dual beacon: 0 * dual CTS protection: 0 * STBC beacon: 0 * L-SIG TXOP Prot: 0 * PCO active: 0 * PCO phase: 0 WPA: * Version: 1 * Group cipher: TKIP * Pairwise ciphers: TKIP CCMP * Authentication suites: PSK RSN: * Version: 1 * Group cipher: TKIP * Pairwise ciphers: TKIP CCMP * Authentication suites: PSK * Capabilities: 1-PTKSA-RC 1-GTKSA-RC (0x0000) WMM: * Parameter version 1 * u-APSD * BE: CW 15-1023, AIFSN 3 * BK: CW 15-1023, AIFSN 7 * VI: CW 7-15, AIFSN 2, TXOP 3008 usec * VO: CW 3-7, AIFSN 2, TXOP 1504 usec WPS: * Version: 1.0 * Wi-Fi Protected Setup State: 2 (Configured) * Response Type: 3 (AP) * UUID: 63041253-1019-2006-1228-b0c554810daa * Manufacturer: D-Link Systems * Model: DIR-619L * Model Number: DIR-619L * Serial Number: 20070413-0001 * Primary Device Type: 6-0050f204-1 * Device name: DIR-619L * Config methods: Display, PBC * Unknown TLV (0x1049, 6 bytes): 00 37 2a 00 01 20 上述的输出中描述了两个不同的wifi源, 我们所需要关注的项主要有两个, 一个是SSID, 这个项即为该wifi的名称, 如Xiaomi_517. 第二个项为WPA, WPA是一种网络加密协议, WPA的版本分为1和2, 从上面我们可以看到, WPA的版本号为1. 4. 连接网络 (1) 如果所连接的网络没有加密, 则可以轻松地直接连接 sudo iw dev wlan0 connect [网络 SSID] (2) 如果网络是用较低级的协议, WEP加密的, 则也比较容易 sudo iw dev wlan0 connect [网络SSID] key 0:[WEP密钥] (3) 如果网络使用的是WPA或者WPA2协议, 则稍微复杂 <1> 安装wpasupplicant sudo apt install wpasupplicant <2> 设置配置文件 sudo vim /etc/wpasupplicant/wpa_supplicant.conf 如果已有该文件, 则备份原有文件, 在新文件中加入如下内容 ctrl_interface=/var/run/wpa_supplicant ap_scan=1 network={ ssid="[your SSID name]" psk="[your WiFi password]" priority=1 } <3> 以上述配置文件启动wpa_supplicant sudo wpa_supplicant -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf & 在该命令中, 最后的&符号意思为将该命令挂到后台运行. 若执行上述命令后出现CONNECTED, 则说明启动成功, 若出现CHANGE或REJECT或其他的, 则说明启动失败. 5. 为本机获取IP地址 sudo dhclient wlan0 6. 检查是否成功连接WIFI 通过iwconfig命令, 查看wlan0是否已经连接上相应SSID的WIFI, 或者通过ping尝试联网.
一. 在配置文件/etc/my.cnf添加一行: skip-grant-tables, 跳过密码验证. 二. 重启mysql数据库主进程 /etc/init.d/mysqld restart 三. 不使用密码登录数据库, 然后修改密码 mysql> use mysql; Database changed mysql> update user set authentication_string=password('yourNewPassword') where user='root' and host='localhost'; Query OK, 1 row affected (0.00 sec) mysql> flush privileges; Query OK, 0 rows affected (0.00 sec) mysql> exit 这里需要修改的字段是authentication_string, 这点和老版本不同. 旧版本为 set password=password(‘admin') 四. 如果你设置的密码太简单, 则在数据库执行任何命令都会报类似如下错误(需要跳到第1步重新开始) mysql> show databases; ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement. mysql> use mysql; ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement. 五. 如果只想设置简单密码需要修改两个全局参数 mysql> set global validate_password_policy=0; Query OK, 0 rows affected (0.00 sec) mysql> set global validate_password_length=1; Query OK, 0 rows affected (0.00 sec) mysql> update user set authentication_string=password('yourNewPassword') where user='root' and host='localhost'; Query OK, 1 row affected (0.00 sec) mysql> use mysql; Database changed
一. Jenkins官网 https://jenkins.io 二. Windows安装Jenkins 1. 下载msi文件并安装 msi下载路径: https://jenkins.io/content/thank-you-downloading-windows-installer/ 2. 访问页面 安装后程序会自动创建了一个Windows服务, Jenkins默认使用的端口是8080, 在浏览器中输入地址: http://127.0.0.1:8080. 3. 更改端口号 方式一. (此方式是命令行启动Jenkins)在Jenkins根目录执行如下命令启动服务: java -jar jenkins.war --httpPort=8081 方式二. (此方式是通过Windows服务启动Jenkins)在Jenkins根目录下的jenkins.xml中搜索httpPort, 将其后面默认的8080改为要设置的端口号, 改好后重新启动Jenkins的Windows服务. 4. 根据提示输入密钥并安装所需要的插件, 如果不知道需要哪些插件, 安装标准配置插件即可. 三. Docker安装Jenkins version: "3.5" services: jenkins: image: jenkins:2.60.3 restart: always container_name: jenkins ports: - "8080:8080" volumes: - type: bind source: /home/paul/docker/myvolume/jenkins/home target: /var/jenkins_home 四. Jenkins配置用户权限 1. 点击左侧的Manage Jenkins --> Configure Global Security, 选择Enable security, Jenkins’ own user database, Allow users to sign up, Matrix-based security, 在Anonymous Users这一行全部打钩, 点击保存. 2. 退出登录, 注册新账户, 然后用新账户登录, 同样点开上一步页面, 取消Allow users to sign up, 取消Anonymous Users这一行的打钩, 在User/group to add这里填写新注册的账户, 点击Add, 在paul这一行全部打钩, 点击保存. 3. 新建的paul用户拥有所有的权限, 可以根据需要更改权限, 并且设置后Jenkins不允许注册新账号 五. Jenkins汉化 1. 个人建议: 各种软件, 官网, 文档等尽量不汉化, 看不懂的去查去学, 毕竟翻译过来的可能会错误理解原意. 2. 使用中文版的Google浏览器, 并把语言设置成了中文. 语言配置在设置页. 3. 安装插件: Manage Jenkins --> Manage Plugins 选中Avaliable这一栏, 在右侧搜索: Locale, 选择Install without restart安装 4. 出现success表示安装成功 5. 安装插件: Manage Jenkins --> Configure System, 找到Locale, 填写zh_CN, 并在Ignore browser...这一项打钩, 保存. 六. Jenkins自动部署Maven项目 1. 在安装了基本配置的那些插件后, 需要再安装两个插件: Maven Integration pluginPublish Over SSH 2. 配置JDK, Maven, Git (1) Manage Jenkins --> Global Tool Configuration (2) 设置本地JDK的安装路径(若不使用本地已有的JDK, 可选中Install automatically, Jenkins会自动安装) (3) 设置本地Maven的安装路径(若不使用本地已有的Maven, 可选中Install automatically, Jenkins会自动安装) (4) 设置Maven自定义配置文件的路径 (5) 设置本地Git的exe路径(若不使用本地已有的Git, 可选中Install automatically, Jenkins会自动安装) 3. 配置SSH Manage Jenkins --> Configure System 在页面中找到Publish over SSH, 点击Add按钮, 然后点击Advanced...按钮并在Use password authentication, or use a different key前面打钩, 填写如下内容: <1>name: SSH连接的名称 <2>Hostname: 远程服务器IP <3>Username: 远程服务器用户名 <4>Remote Directory: 这个是相对于远程服务器的路径, 具体项目中的SSH配置还需要填写Source files, Remote Directory, Remove prefix这三项, Jenkins会通过这几个配置得出最终文件上传后远程服务器中文件的路径. 参考第5(5)<4>步. <5>Passphrase/Password: 远程服务器密码 <6>Path to key: 远程服务器SSH秘钥路径 <7>Port: 远程服务器SSH连接端口号 4. 新建Maven项目 (1) New Item (2) 选择Maven Project, 填写Jenkins项目名称, 点击OK 5. 项目配置说明 (1) Description: 项目描述 (2) Source Code Management: 配置代码管理 <1> 使用Git填写URL, 用户名, 密码, 分支, Jenkins会在安装目录下的workspace目录下一个文件夹, 文件夹名称为当前Jenkins项目的名称, 这个文件夹下存放所有下载的代码. <2> 使用SVNLocal module directory: 用来指定代码存放路径, 这个与Git有所区别, 若不填, 则存放位置与Git类似, 若填写, 则为默认路径的相对路径. 例如: Jenkins安装目录为: C:/Program Files (x86)/Jenkins, 当前Jenkins项目名称为blogs, Local module directory为: all, 则最终代码存放路径为: C:/Program Files (x86)/Jenkins/workspace/blogs/all (3) 自动部署触发器 <1> 可以不设置, 每次手动点击按钮进行一键部署 <2> 可以在上面的各种情况下设置部署, 上图选择的是通过Poll SCM定时部署, H/24 代表每24小时部署一次, 下面还会显示上一次部署时间和下一次部署时间. <3> 也可以通过安装如Github plugin等插件实现每次版本控制器有代码提交, 就自动部署, 但正式环境不建议这么干. (4) 配置pom文件路径与Maven执行命令(Root POM也可以是相对路径) (5) 通过SSH上传文件至远程服务器并执行备份等操作 在Post-build Actions的下拉框中选择Send build artifacts over SSHSSHServer的配置如下:<1>Name: 下拉框选择第3步配置的SSH服务器 <2>Source files: 指定需要上传到远程服务器的文件相对路径(相对于代码存放路径), 例如: 代码存放路径为: C:/Program Files (x86)/Jenkins/workspace/all, Source files为: oa_jinnan/target/oa_jinnan.war, 则上传前文件的最终路径为: C:/Program Files (x86)/Jenkins/workspace/all/oa_jinnan/target/oa_jinnan.war. <3> Remote directory: 参考第5(5)<4>步. <4>Remove prefix: 需要移除的目录前缀, 如果设置了此项属性, 则Source files必须以这个目录前缀开头. 举例说明该属性的作用, 假设配置如下: 系统中SSH配置的Remote directory为: /usr/local/test当前Jenkins项目SSH配置的Source files为: oa_jinnan/target/oa_jinnan.war当前Jenkins项目SSH配置的Remove prefix为: oa_jinnan/target当前Jenkins项目SSH配置的Remote directory为: ../projects/blogs则最终文件上传后远程服务器中文件的路径为: /usr/local/projects/blogs/oa_jinnan.war. 如果不配置当前Jenkins项目SSH配置的Remove prefix, 则最终文件上传后远程服务器中文件的路径为: /usr/local/projects/blogs/oa_jinnan/target/oa_jinnan.war <5>Exec command: 文件上传后, 远程服务器要执行的命令 export DATE=$(date "+%Y%m%d_%H%M%S") sleep 5 cp -rf /usr/local/tomcat/webapps/ROOT /usr/local/bak/oa_$DATE sh /usr/local/tomcat/bin/shutdown.sh netstat -apn |grep java |awk '{print $7}' |xargs |awk -F '/' '{print $1}' |xargs kill -9 rm -rf /usr/local/tomcat/webapps/ROOT cp -rf /usr/local/tomcat/webapps/oa_jinnan/* /usr/local/tomcat/webapps/ROOT rm -rf /usr/local/tomcat/webapps/oa_jinnan.war /usr/local/tomcat/webapps/oa_jinnan sh /usr/local/tomcat/bin/startup.sh 可以不用重启Tomcat, 因为Tomcat会自动解压缩, 视需要而定. export DATE=$(date "+%Y%m%d_%H%M%S")这一句是用来给备份文件添加年月日时分秒的后缀备份也可以在文件上传之前执行, 在Pre Steps的下拉框中选择Send files or execute commands Over SSH, 配置方法与上面相同. netstat -apn |grep java |awk '{print $7}' |xargs |awk -F '/' '{print $1}' |xargs kill -9这一句代表查出java进程的PID, 然后kill掉.
一. 错误信息 Action 10:59:21: INSTALL. MySQL Server 5.7 2: {F08E9C75-A42E-4962-8760-4CBD9CF35D7A} Action 10:59:21: FindRelatedProducts. Searching for related applications Action 10:59:21: AppSearch. Searching for installed applications Action 10:59:21: LaunchConditions. Evaluating launch conditions This application requires Visual Studio 2013 Redistributable. Please install the Redistributable then run this installer again. MySQL Server 5.7 2: {F08E9C75-A42E-4962-8760-4CBD9CF35D7A} 3: 3 The action 'Install' for product 'MySQL Server 5.7.20' failed. 二. 错误原因 MySQL自动安装的Visual C++ Redistributable路径不对或者即使是x64的MySQL识别的也是x86的安装路径. 三. 解决方案 从微软手动下载 Visual C++ Redistributable并安装, 简体中文微软官方下载路径为: https://www.microsoft.com/zh-CN/download/details.aspx?id=40784, 点击下载按钮并将vcredist_x64和vcredist_86都下载下来, 先安装vcredist_x64后尝试重新安装MySQL, 假如依然报错, 然后安装vcredist_x86后再次安装MySQL.
报错信息 mysql命令gruop by报错 this is incompatible with sql_mode=only_full_group_by 在mysql 工具 搜索或者插入数据时报下面错误: ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'database_tl.emp.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by 原因 看一下group by的语法:select 选取分组中的列+聚合函数 from 表名称 group by 分组的列 . 从语法格式来看,是先有分组,再确定检索的列,检索的列只能在参加分组的列中选. 我当前Mysql版本5.7.17,再看一下ONLY_FULL_GROUP_BY的意思:对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么这个SQL是不合法的,因为列不在GROUP BY从句中,也就是说查出来的列必须在group by后面出现否则就会报错,或者这个字段出现在聚合函数里面. 3.查看mysql版本命令:select version();查看sql_model参数命令:SELECT @@GLOBAL.sql_mode;SELECT @@SESSION.sql_mode;输出:ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION其中第一项默认开启ONLY_FULL_GROUP_BY, 解决方法: 1.只选择出现在group by后面的列,或者给列增加聚合函数;(不推荐) 2.命令行输入:set sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';默认关掉ONLY_FULL_GROUP_BY!这个时候 在用工具select 一下:SELECT @@sql_mode;SELECT @@GLOBAL.sql_mode;发现已经不存在ONLY_FULL_GROUP_BY ,感觉已经OK。但是如果你重启Mysql服务的话,发现ONLY_FULL_GROUP_BY还是会存在的 3.想要彻底解决这个问题 就得去改my.ini 配置(如果你们mysql 没有这个文件,就把my-default.ini 改成my.ini,我这个版本就是没有my.ini配置问题) # 在 [mysqld]和[mysql]下添加 sql-mode="STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
001.查看镜像、容器、数据卷所占用的空间 docker system df 002.具体查看镜像内的历史记录 docker history nginx:v2 003.使用Dockerfile构建镜像(注意后面有个点) docker build -t myip . 004.使用compose对docker容器进行编排管理时,需要编写docker-compose.yml文件需要注意缩进 yml文件换行后的缩进,不允许使用tab键字符,只能使用空格,而空格的数量要一致 005.docker-compose 负责实现对 Docker 容器集群的快速编排 006.docker-machine 负责在多种平台上快速安装docker环境 007.swarm mode 负责将多个docker主机封装为单个大型的虚拟dockerd主机,快速打造一套容器云平台 008.安装virtualbox sudo apt-get purge virtualbox sudo apt-get install linux-generic linux-image-generic linux-headers-generic linux-signed-generic sudo apt-get install virtualbox 009.docker镜像加速器下载速度对比 加速器 地址 Httpd,177MB下载镜像耗时 MySQL,407MB下载镜像耗时 Nginx,109MB下载镜像耗时 官方 https://registry.docker-cn.com 52 s 42 s 20 s 阿里 https://2lqq34jg.mirror.aliyuncs.com 36 s 38 s 20 s 网易 http://hub-mirror.c.163.com 67 s 73 s 475 s 官方错误 http://registry.docker-cn.com 1770 s 不忍测试 闲时再测 不使用 --- 一个字慢! 不忍测试 闲时再测 结论:1、使用加速器后,下载速度飞快,家庭100Mb宽带环境下,镜像下载速度能达到3-5MB/s以上。2、由于Docker采用分层文件系统,不同镜像公用一些相同的层文件,在下载后续镜像时下载速度更快,比如阿里加速器下载MySQL镜像,“达到”了10.7MB/s;3、加速器地址一定要写对,官方加速器的不能写成http,一定要写https,否则无加速效果;4、加速器的加速效果差不多?官方的、阿里的、网易163的加速器效果如下:阿里 >官方 > 网易 > 不加速5、Docker支持同时配置多个加速器,建议依上面的次序同时配置多个加速器。6、代码: { "registry-mirrors": [ "https://2lqq34jg.mirror.aliyuncs.com", "https://registry.docker-cn.com", "http://hub-mirror.c.163.com" ] } 010.docker的run命令 docker run -it -v /usr/java/:/mnt/software/ myubuntu /bin/bash docker run <相关参数> <镜像ID 或者 仓库名:标签名> <初始命令> 相关参数包括: -i:表示以“交互模式”运行容器 -t:表示容器启动后会进入其命令行 -v:表示需要将本地哪个目录挂载到容器中,格式:-v <宿主机目录>:<容器目录> 初始命令表示一旦容器启动,需要运行的命令,若此处命令使用"/bin/bash",则表示什么也不做,只需进入命令行即可 退出容器使用Ctrl+d或输入exit 再次启动已启动过但现在是关闭的容器 docker start 容器ID或容器名 这个命令只会启动容器,不会进入容器。要进入容器得用命令 docker attach 容器ID或容器名 011.docker如何查看已存在的容器所挂载的目录 docker inspect container_name | grep Mounts -A 20 012.docker启动mysql容器 初次启动需要指定root用户密码, 也可在docker-compose中指定, 直接用docker-compose启动 docker run -e MYSQL_ROOT_PASSWORD=root -p 33066:3306 --name mysql-5.7 -d mysql:5.7 -v /data/mysql/my.cnf:/etc/mysql/mysql.conf.d -v /data/mysql/logs:/usr/local/mysql/logs -v /data/mysql/data:/var/lib/mysql 013.docker进入mysql容器 docker exec -it mysql-5.7 bash # 然后进入mysql服务 mysql -uroot -p 014.docker启动tomcat docker run --mount source=tomcat-8.5-xyj,target=/usr/local/tomcat/webapps -p 8081:8080 --name tomcat-8.5 -d tomcat:8.5 015.DockerCompose通过compose工程名以及服务名从dockerEngine获取当前所有含有此标记的容器以检查当前工程所包含的服务状态,根据当前状态为每个服务制定接下来的动作 若容器不存在,则服务动作设置为创建(create) 若容器存在但设置不允许重建,则服务动作设置为启动(start) 若容器配置发生变化(config-hash)或者设置强制重建标志,则服务动作设置为重建(recreate) 若容器状态为停止,则服务动作设置为启动(start) 若容器状态为运行但其依赖容器需要重建,则服务状态设置为重建(recreate) 若容器状态为运行其无配置改变则不作操作 016.docker查看某个容器大小 进入docker容器默认位置:/var/lib/docker/containers, 文件夹名称即为容器名,文件夹大小即为容器大小 17. Docker参考网站 Docker Hub官方网站(用于查找各种镜像): https://hub.docker.com/docker-compose.yml文件各个参数的官方说明: https://docs.docker.com/compose/compose-file/ 18. Docker的各种docker-compose.yml文件 (1) MySQL version: "3.5" services: mysql: image: mysql:5.7 restart: always container_name: mysql environment: MYSQL_ROOT_PASSWORD: root ports: - "3306:3306" networks: mysql: ipv4_address: 172.20.0.2 volumes: - type: volume source: data target: /var/lib/mysql - type: volume source: config target: /etc/mysql/mysql.conf.d - type: volume source: logs target: /usr/local/mysql/logs volumes: data: config: logs: networks: mysql: driver: bridge name: mysql ipam: driver: default config: - subnet: 172.20.0.0/24 (2) Redis version: "3.5" services: redis: image: redis:4.0.9 restart: always container_name: redis volumes: - type: volume source: config target: /usr/local/etc/redis - type: volume source: data target: /data command: redis-server /usr/local/etc/redis/redis.conf ports: - "6379:6379" networks: redis: ipv4_address: 172.20.0.2 volumes: config: data: networks: redis: driver: bridge name: redis ipam: driver: default config: - subnet: 172.20.0.0/24 (3) Tomcat version: "3.5" services: blog: image: tomcat:8.5 restart: always container_name: blog ports: - "8083:8080" networks: - mysql volumes: - type: volume source: blog target: /usr/local/tomcat/webapps volumes: blog: name: blog networks: mysql: external: true name: mysql (4) Java示例(执行了java -jar /opt/blogback.jar命令, 方便启动容器后自动运行Java程序, 也可用于SpringBoot项目的部署) version: "3.5" services: blogback: image: java:8 restart: always container_name: blogback ports: - "8082:8080" working_dir: /opt command: java -jar /opt/blogback.jar networks: - mysql volumes: - type: volume source: blogback target: /opt volumes: blogback: name: blogback networks: mysql: external: true name: mysql (5) GitLab version: "3.5" services: gitlab: image: gitlab/gitlab-ce:10.5.4-ce.0 restart: always container_name: gitlab ports: - "8085:80" - "2222:22" hostname: "gitlab.ywz.com" environment: GITLAB_OMNIBUS_CONFIG: | gitlab_rails['gitlab_shell_ssh_port'] = 2222 volumes: - type: volume source: config target: /etc/gitlab - type: volume source: logs target: /var/log/gitlab - type: volume source: data target: /var/opt/gitlab volumes: config: name: gitlab_config logs: name: gitlab_logs data: name: gitlab_data (6) Jenkins version: "3.5" services: jenkins: image: jenkins:2.60.3 restart: always container_name: jenkins ports: - "8080:8080" volumes: - type: bind source: /home/paul/docker/myvolume/jenkins/home target: /var/jenkins_home (7) Nexus version: "3.5" services: nexus: image: sonatype/nexus3:3.8.0 restart: always container_name: nexus ports: - "8081:8081" volumes: - type: volume source: data target: /nexus-data volumes: data: (8) Nginx version: "3.5" services: nginx: image: nginx:1.13 restart: always container_name: nginx ports: - "80:80" volumes: - type: volume source: config target: /etc/nginx volumes: config: (9) Python version: "3.5" services: python: image: python:3.5 restart: always container_name: python tty: true command: bash volumes: - type: volume source: workspace target: /home - type: volume source: lib target: /usr/local/lib volumes: workspace: name: python_workspace lib: name: python_lib (10) 多个Tomcat项目共用MySQL, Redis示例 version: "3.5" services: jn: image: tomcat:8.5 restart: always container_name: tomcat_oa_jn ports: - "8082:8080" networks: - mysql_oa - redis_oa volumes: - type: bind source: /home/paul/docker/myvolume/tomcat_oa_jn/webapps target: /usr/local/tomcat/webapps depends_on: - mysql_oa - redis_oa xq: image: tomcat:8.5 restart: always container_name: tomcat_oa_xq ports: - "8083:8080" networks: - mysql_oa - redis_oa volumes: - type: bind source: /home/paul/docker/myvolume/tomcat_oa_xq/webapps target: /usr/local/tomcat/webapps depends_on: - mysql_oa - redis_oa test: image: tomcat:8.5 restart: always container_name: tomcat_oa_test ports: - "8084:8080" networks: - mysql_oa - redis_oa volumes: - type: bind source: /home/paul/docker/myvolume/tomcat_oa_test/webapps target: /usr/local/tomcat/webapps depends_on: - mysql_oa - redis_oa mysql_oa: image: mysql:5.7 restart: always container_name: mysql_oa environment: MYSQL_ROOT_PASSWORD: root ports: - "3307:3306" networks: mysql_oa: ipv4_address: 172.20.0.2 volumes: - type: volume source: mysql_data target: /var/lib/mysql - type: volume source: mysql_config target: /etc/mysql/mysql.conf.d - type: volume source: mysql_logs target: /usr/local/mysql/logs redis_oa: image: redis:4.0.9 restart: always container_name: redis_oa command: redis-server /usr/local/etc/redis/redis.conf ports: - "6379:6379" networks: redis: ipv4_address: 172.21.0.2 volumes: - type: volume source: redis_config target: /usr/local/etc/redis - type: volume source: redis_data target: /data volumes: mysql_data: name: mysql_oa_data mysql_config: name: mysql_oa_config mysql_logs: name: mysql_oa_logs redis_config: name: redis_oa_config redis_data: name: redis_oa_data networks: mysql_oa: driver: bridge name: mysql_oa ipam: driver: default config: - subnet: 172.20.0.0/24 redis_oa: driver: bridge name: redis_oa ipam: driver: default config: - subnet: 172.21.0.0/24 19. Dockerfile实现在centos7-jdk8容器中安装应用(以libreoffice为例) (1) Dockerfile文件 FROM bpatterson/centos7-jdk8 RUN yum update -y RUN yum install -y libreoffice-headless libreoffice-writer libreoffice-calc libreoffice- libreoffice-impress libreoffice-langpack-zh-Hans libreoffice-langpack-zh-Hant libreoffice-langpack-ja ImageMagick curl RUN yum clean all WORKDIR / (2) 在Dockerfile文件所在目录下执行如下命令生成镜像 docker build -t libreoffice:1.0 . (3) 镜像生成后就可以通过compose文件或者直接使用命令启动容器了 version: "3.3" services: libreoffice: image: libreoffice:1.0 restart: always tty: true command: /bin/bash container_name: libreoffice ports: - "8192:8080" volumes: - type: bind source: /home/libreoffice/data target: /home/libreoffice/data (4) 启动容器后运行容器内应用 docker exec -t libreoffice libreoffice --headless --convert-to pdf /home/libreoffice/data/source/test.xls --outdir /home/libreoffice/data/target (5) libreoffice功能实现附件格式转换, 如: xls文件转换为doc文件, doc文件转换为pdf文件等等.
一. 下载地址 http://maven.apache.org/download.cgi 二. 配置系统环境(根据需要配或不配) 1. MAVEN_HOME C:apache-maven-3.3.3 2. PATH追加(注意, 如果原来末尾没有英文分号, 需要加上英文分号后追加) %MAVEN_HOME%bin 3. CMD界面输入MVN -V后出现版本号, 则说明配置成功 三. 更改Maven的仓库默认存放地址 修改C:apache-maven-3.3.3 下的 conf 文件夹下的 settings.xml文件, 更改localRepository配置节点: <localRepository>E:/workspace/maven/repo</localRepository> 四. 配置Maven的阿里云镜像中央仓库 修改C:apache-maven-3.3.3下的conf文件夹下的 settings.xml文件 <mirrors> <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror> </mirrors> 或者直接在项目中的pom文件中指定 <!--================== JAR包镜像 ==================--> <repositories> <repository> <id>aLiYun</id> <url>https://maven.aliyun.com/repository/public</url> <releases> <enabled>true</enabled> </releases> </repository> </repositories> 五. 修改所有Maven项目默认JDK版本 修改C:apache-maven-3.3.3下的conf文件夹下的 settings.xml文件 <profiles> <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> </profiles> 六. 修改某个maven项目的默认JDK版本, 在Maven项目的pom文件加入如下代码 <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> <showWarnings>true</showWarnings> </configuration> </plugin> 七. 下载Maven相关包 在CMD中敲并回车执行: mvn help:system 八. 在Myeclipse中使用Maven 1.打开myeclipse2014 选择 window -> prefences -> MyEclipse 下的-> Maven4MyEclipse 1、修改 " Maven4MyEclipse" 下的Installations 点击 ” Add “ 选择目录 ” C:apache-maven-3.3.3“ Global settings from installation directory( open file) 选择C:apache-maven-3.3.3confsettings.xml 修改"Maven4MyEclipse" 下的 User Settings 下的 User Settings 属性” C:apache-maven-3.3.3confsettings.xml“, 保存确认. 九. 几个可用的仓库地址 http://maven.aliyun.com/nexus/content/groups/public/https://repository.jboss.org/nexus/content/groups/public/http://mirrors.ibiblio.org/pub/mirrors/maven2/http://repo2.maven.org/maven2/http://uk.maven.org/maven2/ 十. 标准settings.xml配置文件 <?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <!-- | This is the configuration file for Maven. It can be specified at two levels: | | 1. User Level. This settings.xml file provides configuration for a single user, | and is normally provided in ${user.home}/.m2/settings.xml. | | NOTE: This location can be overridden with the CLI option: | | -s /path/to/user/settings.xml | | 2. Global Level. This settings.xml file provides configuration for all Maven | users on a machine (assuming they're all using the same Maven | installation). It's normally provided in | ${maven.conf}/settings.xml. | | NOTE: This location can be overridden with the CLI option: | | -gs /path/to/global/settings.xml | | The sections in this sample file are intended to give you a running start at | getting the most out of your Maven installation. Where appropriate, the default | values (values used when the setting is not specified) are provided. | |--> <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 | The path to the local repository maven will use to store artifacts. | | Default: ${user.home}/.m2/repository --> <localRepository>E:\repository</localRepository> <!-- interactiveMode | This will determine whether maven prompts you when it needs input. If set to false, | maven will use a sensible default value, perhaps based on some other setting, for | the parameter in question. | | Default: true <interactiveMode>true</interactiveMode> --> <!-- offline | Determines whether maven should attempt to connect to the network when executing a build. | This will have an effect on artifact downloads, artifact deployment, and others. | | Default: false <offline>false</offline> --> <!-- pluginGroups | This is a list of additional group identifiers that will be searched when resolving plugins by their prefix, i.e. | when invoking a command line like "mvn prefix:goal". Maven will automatically add the group identifiers | "org.apache.maven.plugins" and "org.codehaus.mojo" if these are not already contained in the list. |--> <pluginGroups> <!-- pluginGroup | Specifies a further group identifier to use for plugin lookup. <pluginGroup>com.your.plugins</pluginGroup> --> </pluginGroups> <!-- proxies | This is a list of proxies which can be used on this machine to connect to the network. | Unless otherwise specified (by system property or command-line switch), the first proxy | specification in this list marked as active will be used. |--> <proxies> <!-- proxy | Specification for one proxy, to be used in connecting to the network. | <proxy> <id>optional</id> <active>true</active> <protocol>http</protocol> <username>proxyuser</username> <password>proxypass</password> <host>proxy.host.net</host> <port>80</port> <nonProxyHosts>local.net|some.host.com</nonProxyHosts> </proxy> --> </proxies> <!-- servers | This is a list of authentication profiles, keyed by the server-id used within the system. | Authentication profiles can be used whenever maven must make a connection to a remote server. |--> <servers> <!-- server | Specifies the authentication information to use when connecting to a particular server, identified by | a unique name within the system (referred to by the 'id' attribute below). | | NOTE: You should either specify username/password OR privateKey/passphrase, since these pairings are | used together. | <server> <id>deploymentRepo</id> <username>repouser</username> <password>repopwd</password> </server> --> <!-- Another sample, using keys to authenticate. <server> <id>siteServer</id> <privateKey>/path/to/private/key</privateKey> <passphrase>optional; leave empty if not used.</passphrase> </server> --> </servers> <!-- mirrors | This is a list of mirrors to be used in downloading artifacts from remote repositories. | | It works like this: a POM may declare a repository to use in resolving certain artifacts. | However, this repository may have problems with heavy traffic at times, so people have mirrored | it to several places. | | That repository definition will have a unique id, so we can create a mirror reference for that | repository, to be used as an alternate download site. The mirror site will be the preferred | server for that repository. |--> <mirrors> <!-- mirror | Specifies a repository mirror site to use instead of a given repository. The repository that | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used | for inheritance and direct lookup purposes, and must be unique across the set of mirrors. |--> <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror> </mirrors> <!-- profiles | This is a list of profiles which can be activated in a variety of ways, and which can modify | the build process. Profiles provided in the settings.xml are intended to provide local machine- | specific paths and repository locations which allow the build to work in the local environment. | | For example, if you have an integration testing plugin - like cactus - that needs to know where | your Tomcat instance is installed, you can provide a variable here such that the variable is | dereferenced during the build process to configure the cactus plugin. | | As noted above, profiles can be activated in a variety of ways. One way - the activeProfiles | section of this document (settings.xml) - will be discussed later. Another way essentially | relies on the detection of a system property, either matching a particular value for the property, | or merely testing its existence. Profiles can also be activated by JDK version prefix, where a | value of '1.4' might activate a profile when the build is executed on a JDK version of '1.4.2_07'. | Finally, the list of active profiles can be specified directly from the command line. | | NOTE: For profiles defined in the settings.xml, you are restricted to specifying only artifact | repositories, plugin repositories, and free-form properties to be used as configuration | variables for plugins in the POM. | |--> <profiles> <!-- profile | Specifies a set of introductions to the build process, to be activated using one or more of the | mechanisms described above. For inheritance purposes, and to activate profiles via <activatedProfiles/> | or the command line, profiles have to have an ID that is unique. | | An encouraged best practice for profile identification is to use a consistent naming convention | for profiles, such as 'env-dev', 'env-test', 'env-production', 'user-jdcasey', 'user-brett', etc. | This will make it more intuitive to understand what the set of introduced profiles is attempting | to accomplish, particularly when you only have a list of profile id's for debug. | | This profile example uses the JDK version to trigger activation, and provides a JDK-specific repo.--> <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> <!-- | Here is another profile, activated by the system property 'target-env' with a value of 'dev', | which provides a specific path to the Tomcat instance. To use this, your plugin configuration | might hypothetically look like: | | ... | <plugin> | <groupId>org.myco.myplugins</groupId> | <artifactId>myplugin</artifactId> | | <configuration> | <tomcatLocation>${tomcatPath}</tomcatLocation> | </configuration> | </plugin> | ... | | NOTE: If you just wanted to inject this configuration whenever someone set 'target-env' to | anything, you could just leave off the <value/> inside the activation-property. | <profile> <id>env-dev</id> <activation> <property> <name>target-env</name> <value>dev</value> </property> </activation> <properties> <tomcatPath>/path/to/tomcat/instance</tomcatPath> </properties> </profile> --> </profiles> <!-- activeProfiles | List of profiles that are active for all builds. | <activeProfiles> <activeProfile>alwaysActiveProfile</activeProfile> <activeProfile>anotherAlwaysActiveProfile</activeProfile> </activeProfiles> --> </settings>
一. Java项目连接MySQL时报错: "The last packet sent successfully to the server was 0 milliseconds ago." 1. 出错原因 数据库回收了连接, 而系统的缓冲池不知道, 继续使用被回收的连接. 2. 解决方法 方法一. 将MySQL回收空闲连接的时间变长, MySQL默认回收时间是8小时, 可以在MySQL目录下的my.ini中增加下面配置, 将时间改为1天(单位是秒) [mysqld] wait_timeout=86400 方法二. 可以通过配置, 让缓冲池去测试连接是否被回收, 如果被回收, 则不继续使用, DBCP添加如下配置 # SQL查询,用来验证从连接池取出的连接 dbcp.validationQuery=SELECT 1 # 指明连接是否被空闲连接回收器(如果有)进行检验,如果检测失败,则连接将被从池中去除 dbcp.testWhileIdle=true # 在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位,一般比minEvictableIdleTimeMillis小 dbcp.timeBetweenEvictionRunsMillis=300000 # 在每次空闲连接回收器线程(如果有)运行时检查的连接数量,最好和maxActive一致 dbcp.numTestsPerEvictionRun=50 # 连接池中连接,在时间段内一直空闲,被逐出连接池的时间(1000*60*60),以毫秒为单位 dbcp.minEvictableIdleTimeMillis=3600000 二. Linux启动Java项目报错: Get local host name failed.java.net.UnknownHostException. 1. 详细错误信息如下 ERROR - Get local host name failed -com.trs.infra.cluster.ClusterConfig.getMemberHost(ClusterConfig.java:293) java.net.UnknownHostException: localhost: localhost at java.net.InetAddress.getLocalHost(InetAddress.java:1353) at xxxxxxx 产品异常信息 at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1029) at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:862) at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4013) at org.apache.catalina.core.StandardContext.start(StandardContext.java:4357) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:823) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:807) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:595) at org.apache.catalina.core.StandardHostDeployer.install(StandardHostDeployer.java:277) at org.apache.catalina.core.StandardHost.install(StandardHost.java:832) at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:701) at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:432) at org.apache.catalina.startup.HostConfig.start(HostConfig.java:983) at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:349) at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1091) at org.apache.catalina.core.StandardHost.start(StandardHost.java:789) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1083) at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:478) at org.apache.catalina.core.StandardService.start(StandardService.java:480) at org.apache.catalina.core.StandardServer.start(StandardServer.java:2313) at org.apache.catalina.startup.Catalina.start(Catalina.java:556) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:287) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:425) 2. 出错的Java代码 InetAddress localhost = InetAddress.getLocalHost(); 3. 分析问题 ping 127.0.0.1 可以ping通 ping localhost 不通 说明是主机映射的原因 4. 解决方法 在Linux的/etc/hosts文件最后一行加入如下代码 127.0.0.1 www.paulandcode.com localhost 第一部份: 网络IP地址第二部份: 主机名或域名第三部份: 主机名别名 三. Java, Kettle, Jenkins等第三方插件执行Linux的sudo命令时报错: sudo: no tty present and no askpass program specified 1. 这是因为非root账号执行sudo时需要密码, 可以设置免密码. 2. 进入到root用户下 3. 给/etc/sudoers文件添加写权限 chmod u+w /etc/sudoers 4. 添加免密码 abc ALL = NOPASSWD: ALL 四. 阿里云的Linux报错: sudo: unable to resolve host [hostname] 1. 执行sudo vim /etc/hosts编辑原文件如下 127.0.0.1 localhost # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters 2. 在第一行下面添加如下代码 127.0.0.1 [hostname] 3. 如果觉得主机名太长, 可以在/etc/hostname里面修改, 重启后生效. 五. Kettle报错: Unexpected problem reading shared objects from XML file:null 1. 原因 将数据库链接进行了共享, 然后删除共享. 再次保存转换时报错.或者DB连接为中文, 也会报这个错误. 2. 解决 在C:/Administrator/.kettle文件夹下, 找到share.xml, 在文件中找到sharedobjects节点, 将想要删除的共享对应的子节点删除. 六. ORA-01810: 格式代码出现两次 1. 错误原因 Oracle中格式化时间时出错(分钟不能用java中的mm), 出错Sql代码: TO_DATE('2011-09-24 00:00:00','YYYY-MM-DD HH:mm:ss') 2. 正确的Sql如下: TO_DATE('2011-09-01 00:00:00','YYYY-MM-DD HH24:MI:SS') 七. Java报错: SEVERE: Unable to process Jar entry [......]for annotations java.io.EOFException 可能原因: 1. jar包损坏, 需删掉jar包重新下载 2. Tomcat版本, 遇到过的情况: 使用8.0.9版本Tomcat启动报这个错, 改成8.0.22版本就不报错了. 3. 一个Tomcat中部署了两个同样的项目,一个war,一个由该war解压的文件夹,删掉一个即可 八. Tomcat启动报错: Unsupported major.minor version 52.0 1. 错误原因 不支持JDK1.8, 在编译时使用的时JDK1.8, 而运行时使用的JDK版本低于1.8 2. 解决方案 指定Tomcat运行时JDK版本(若不指定, 会使用默认版本)在Tomcat安装目录下的bin目录找到setclasspath.bat这个文件, 编辑文件, 在第一行加入如下代码 set JAVA_HOME=D:\Program Files\Java\jdk8\jdk1.8.0_51 set JRE_HOME=D:\Program Files\Java\jdk8\jre8 九. 启动Tomcat报错: IllegalArgumentException: The main resource set specified ... is not valid 1. 错误信息 java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/spring]] at java.util.concurrent.FutureTask.report(Unknown Source) at java.util.concurrent.FutureTask.get(Unknown Source) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:941) at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:872) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1421) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1411) at java.util.concurrent.FutureTask.run(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/spring]] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167) ... 6 more Caused by: org.apache.catalina.LifecycleException: Failed to start component [org.apache.catalina.webresources.StandardRoot@19d5011c] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167) at org.apache.catalina.core.StandardContext.resourcesStart(StandardContext.java:4868) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5003) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) ... 6 more Caused by: java.lang.IllegalArgumentException: The main resource set specified [D:\Users\chengyq\eclipse-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\spring] is not valid at org.apache.catalina.webresources.StandardRoot.createMainResourceSet(StandardRoot.java:748) at org.apache.catalina.webresources.StandardRoot.startInternal(StandardRoot.java:706) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) ... 9 more 2. 错误原因 之前创建了一个名为spring的项目,已经删除, 但是server中还有这个项目。现在运行其他项目,报错找不到已经删除的项目。 3. 解决方法 (1) 找到如下路径: workspacemetadatapluginsorg.eclipse.wst.server.coretmp0conf, 将其中已删除项目对应的标签删除。 (2) 删除Eclipse左侧Servers中对应的Server.xml文件中多余的配标签 十. Arrays.asList返回的List无法直接使用add()方法, Java报错: java.lang.UnsupportedOperationException 1. 报错代码 String[] array = {"1","2","3","4","5"}; List<String> list = Arrays.asList(array); list.add("6"); 2. 报错信息 Exception in thread "main" java.lang.UnsupportedOperationException at java.util.AbstractList.add(AbstractList.java:148) at java.util.AbstractList.add(AbstractList.java:108) at com.paulandcode.test.ListTest.main(ListTest.java:11) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) 3. 错误分析 调用了Arrays.asList()生产的List的add、remove方法时报异常, 这是由Arrays.asList() 返回的是Arrays的内部类ArrayList, 而不是java.util.ArrayList. Arrays的内部类ArrayList和java.util.ArrayList都是继承AbstractList, remove、add等方法AbstractList中是默认throw UnsupportedOperationException而且不作任何操作. java.util.ArrayList重新了这些方法而Arrays的内部类ArrayList没有重新, 所以会抛出异常. 4. 解决错误 String[] array = {"1","2","3","4","5"}; List<String> list = Arrays.asList(array); List<String> arrList = new ArrayList<String>(list); arrList.add("6");
一. 除了调用接口查询城市, 还可以通过离线文件查询城市, 使用GeoLite2 City库 二. 离线库下载地址: https://dev.maxmind.com/geoip/geoip2/geolite2/ 点击如下位置下载压缩文件 文件解压后有一个文件名为GeoLite2-City.mmdb, 这就是我们的离线库 三. 导包 <dependency> <groupId>com.maxmind.geoip2</groupId> <artifactId>geoip2</artifactId> <version>2.8.1</version> </dependency> 四. 编写工具类 package com.product.utils; import java.net.InetAddress; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.maxmind.geoip2.DatabaseReader; /** * * @description: 获取客户端IP地址 * @author: paulandcode * @email: paulandcode@gmail.com * @since: 2018年9月17日 下午3:44:51 */ public class IPUtils { private static Logger logger = LoggerFactory.getLogger(IPUtils.class); /** * 获取客户端IP地址 * * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址 * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址 */ public static String getIP(HttpServletRequest request) { String ip = null; try { ip = request.getHeader("x-forwarded-for"); if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } } catch (Exception e) { logger.error("IPUtils ERROR ", e); } return ip; } /** * * @description: 获得国家 * @param reader * @param ip * @return * @throws Exception */ public static String getCountry(DatabaseReader reader, String ip) throws Exception { return reader.city(InetAddress.getByName(ip)).getCountry().getNames().get("zh-CN"); } /** * * @description: 获得省份 * @param reader * @param ip * @return * @throws Exception */ public static String getProvince(DatabaseReader reader, String ip) throws Exception { return reader.city(InetAddress.getByName(ip)).getMostSpecificSubdivision().getNames().get("zh-CN"); } /** * * @description: 获得城市 * @param reader * @param ip * @return * @throws Exception */ public static String getCity(DatabaseReader reader, String ip) throws Exception { return reader.city(InetAddress.getByName(ip)).getCity().getNames().get("zh-CN"); } /** * * @description: 获得经度 * @param reader * @param ip * @return * @throws Exception */ public static Double getLongitude(DatabaseReader reader, String ip) throws Exception { return reader.city(InetAddress.getByName(ip)).getLocation().getLongitude(); } /** * * @description: 获得纬度 * @param reader * @param ip * @return * @throws Exception */ public static Double getLatitude(DatabaseReader reader, String ip) throws Exception { return reader.city(InetAddress.getByName(ip)).getLocation().getLatitude(); } } 五. main方法测试 // String path = req.getSession().getServletContext().getRealPath("/WEB-INF/classes/GeoLite2-City.mmdb"); String path = "E:/GeoLite2-City.mmdb"; // 创建 GeoLite2 数据库 File database = new File(path); // 读取数据库内容 DatabaseReader reader = new DatabaseReader.Builder(database).build(); // 访问IP String ip = "36.157.208.62"; String site = IPUtils.getCountry(reader, ip) + "-" + IPUtils.getProvince(reader, ip) + "-" + IPUtils.getCity(reader, ip); System.out.println(site);
1. Nginx中/etc/nginx/nginx.conf的常用配置及说明 # 指定Nginx Worker进程运行用户, 语法: user user [group] user nginx; # worker进程数, 通常设置成和CPU的数量相等, 默认为1. worker_processes 1; # 指定进程id存储文件 pid /run/nginx.pid; # 事件模块 events { # 每个worker进程的连接数, 通过worker_connections和worker_proceses可以计算出maxclients: # max_clients = worker_processes * worker_connections, 作为反向代理时, max_clients为: # max_clients = worker_processes * worker_connections/4 worker_connections 768; # 若开启此配置, 则Nginx会在接到一个新的连接通知之后, 尽可能多地去接受, 默认为: off multi_accept off; } # http核心模块 http { ## # 基本设置 ## # 是否启动高效传输文件模式, sendfile可以让Nginx在传输文件时直接在磁盘和tcp socket之间传输数据. # 如果这个参数不开启, 会先在用户空间(Nginx进程空间)申请一个buffer, 用read函数把数据从磁盘读到cache, # 再从cache读取到用户空间的buffer, 再用write函数把数据从用户空间的buffer写入到内核的buffer, # 最后到tcp socket. 开启这个参数后可以让数据不用经过用户buffer, 默认off. sendfile on; # 必须在sendfile开启模式才有效, 告诉Nginx在一个数据包里发送所有头文件, 而不一个接一个的发送, 默认off. tcp_nopush on; # 告诉Nginx不要缓存数据, 而是一段一段的发送, 当需要及时发送数据时, 就应该开启这个功能, # 这样发送一小块数据信息时就能够立即得到返回值, 默认on. tcp_nodelay on; # 给客户端分配keep-alive链接超时时间, 服务器将在这个超时时间过后关闭链接. # 我们将它设置低些可以让Ngnix持续工作的时间更长. keepalive_timeout 65; # 影响散列表的冲突率, types_hash_max_size越大, 就会消耗更多的内存, 但散列key的冲突率会降低, # 检索速度就更快. types_hash_max_size越小, 消耗的内存就越小, 但散列key的冲突率可能上升. types_hash_max_size 2048; # 是否显示版本号, 若不显示, 浏览器访问时抓包, 查看HTTP响应的Server头没有版本号, 默认on server_tokens on; # 保存服务器名字的hash表是由指令server_names_hash_max_size和server_names_hash_bucket_size所控制, # 若Nginx给出需要增大hash max size或hash bucket size的提示, 那么首要的是增大前一个参数的大小. # server_names_hash_max_size 512; # server_names_hash_bucket_size 64; # 若为off, 则始终按照默认的80端口, 若为on, 则返回当前正在监听的端口, 默认on. port_in_redirect on; # 若为off, 则会以当前服务器的IP地址进行拼接URL. 若为on, 则会首先查找server_name, # 若没有找到, 则会查找请求头的HOST字段, 若还是没有, 则以当前服务器的IP进行拼接, 默认on. server_name_in_redirect on; # 设定MIME类型, 类型由mime.type文件定义. include /etc/nginx/mime.types; # 设定默认的MIME类型, 默认: text/plain. default_type application/octet-stream; # 设置上传文件大小最大为1000m, 超过会报413错误 client_max_body_size 1000m; ## # SSL协议设置 ## # 用于指定支持的加密协议. ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE # 设置协商加密算法时, 优先使用服务端的加密套件, 而不是客户端浏览器的加密套件, 默认off. ssl_prefer_server_ciphers off; ## # 日志设置 ## # 每一个访问请求的记录位置 access_log /var/log/nginx/access.log; # Nginx错误信息的记录位置 error_log /var/log/nginx/error.log; ## # Gzip压缩设置 ## # 是否启动Gzip gzip on; # IE6的某些版本对gzip的压缩支持很不好, 会造成页面的假死, # 对img进行Gzip后造成IE6的假死, 把对img的Gzip压缩去掉后就正常了. gzip_disable "msie6"; # 和HTTP头有关系, 加个vary头, 给代理服务器用的, 有的浏览器支持压缩, 有的不支持, # 为了避免浪费不支持的也压缩, 根据客户端的HTTP头来判断, 是否需要压缩. gzip_vary on; # Nginx作为反向代理的时候该参数起作用, 根据某些请求和应答来决定是否在对代理请求的应答启用Gzip压缩, # 是否压缩取决于请求头中的"Via"字段, 指令中可以同时指定多个不同的参数, 可选值值为: # off - 关闭所有的代理结果数据的压缩 # expired - 启用压缩,如果header头中包含 "Expires" 头信息 # no-cache - 启用压缩,如果header头中包含 "Cache-Control:no-cache" 头信息 # no-store - 启用压缩,如果header头中包含 "Cache-Control:no-store" 头信息 # private - 启用压缩,如果header头中包含 "Cache-Control:private" 头信息 # no_last_modified - 启用压缩,如果header头中不包含 "Last-Modified" 头信息 # no_etag - 启用压缩 ,如果header头中不包含 "ETag" 头信息 # auth - 启用压缩 , 如果header头中包含 "Authorization" 头信息 # any - 无条件启用压 # 默认为off. gzip_proxied off; # Gzip压缩比, 值为1~9, 1的压缩比最小处理速度最快, 9的压缩比最大但处理最慢(传输快但比较消耗CPU) gzip_comp_level 6; # 设置允许压缩的页面最小字节数, 默认值是0, 不管页面多大都压缩, 建议设置大于1k(即1024), 小于1k可能会越压越大. gzip_min_length 1024; # 设置系统获取几个单位的缓存用于存储Gzip的压缩结果数据流, 4 8k代表: 按照原始数据大小以8k为单位的4倍申请内存. gzip_buffers 4 8k; # 匹配MIME类型进行压缩 gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; # 识别HTTP的协议版本, 99.99%的浏览器都支持1.1, 所以可以不用设这个值, 保持系统默认即可, 默认1.1. gzip_http_version 1.1; ## # 虚拟主机设置 ## # Nginx的配置很灵活, 支持include配置文件, 如果我们的域名都配置到nginx.conf, 那么这个文件就会比较乱, # 也影响管理和阅读, 所以直接拆分出来, 分成不同的配置文件. include /etc/nginx/conf.d/*.conf; # 加载一个外部的配置文件, sites-enabled文件夹下只有一个default文件, # 这个外部的配置文件就是负责我们Nginx的默认代理, 也就是server块的配置. include /etc/nginx/sites-enabled/*; ## # 缓存设置 ## # 缓存文件路径 # levels=1:2 设置目录深度, 第一层目录是1个字符, 第2层是2个字符. # keys_zone 设置web缓存名称和内存缓存空间大小. # inactive 自动清除缓存文件时间. # max_size 硬盘空间最大可使用值, 如果缓存空间满, 默认覆盖掉缓存时间最长的资源. proxy_cache_path /data/proxy/cache levels=1:2 keys_zone=cache_one:500m inactive=7d max_size=10g; # 指定临时缓存文件的存储路径(路径需和上面路径在同一分区) proxy_temp_path /data/proxy/temp; } # 配置邮件服务器 #mail { # # See sample authentication script at: # # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript # # # 指定Nginx提供邮件服务时, 用于HTTP认证的服务地址 # # auth_http localhost/auth.php; # # 指定现有客户端上的POP3协议的扩展 # # pop3_capabilities "TOP" "USER"; # # 指定现有客户端上的IMAP协议的扩展 # # imap_capabilities "IMAP4rev1" "UIDPLUS"; # # server { # # 指定邮件服务器监听的IP地址和端口. # listen localhost:110; # # 指定虚拟机支持的加密协议. # protocol pop3; # # 是否开启邮件代理 # proxy on; # } # # server { # # 指定邮件服务器监听的IP地址和端口. # listen localhost:143; # # 指定虚拟机支持的加密协议. # protocol imap; # # 是否开启邮件代理 # proxy on; # } #} 2. Nginx中/etc/nginx/sites-enabled/default的常用配置及说明 server { # Nginx监听的IP及端口号, 可以监听多个 listen 127.0.0.1:80; # Nginx监听的IPv6的IP及端口号 listen [::]:80; # SSL协议配置 # listen 443 ssl default_server; # listen [::]:443 ssl default_server; # 加载配置片段 # include snippets/snakeoil.conf; # 指定哪个目录作为根目录, 用于文件的检索 root /var/www/html; # 在上面指定的根目录下, 找到如下页面, 作为Nginx的默认主页 index index.html index.htm index.nginx-debian.html; # 配置server的多域名, 域名可以通过以下方式: # 1. 完整的域名, 如: www.example.com # 2. 带*号开头的域名, 如: *.example.com # 3. 带*号末尾的域名, 如: mail.* # 4. 可匹配的正则表达式 server_name www.paulandcode.com; location / { # 原请求不存在时, 重定向到指定的URI, 并返回结果(此处设定为404) try_files $uri $uri/ =404; } # 静态文件的处理 location ~ ^/(images|javascript|js|css|flash|media|static)/ { # 设置被代理服务器的地址, 包含传输协议, 主机名称或IP地址加端口号, URI等要素. proxy_pass http://www.paulandcode.com:8080; # 自定义http header头, 用于发送给后端真实服务器. proxy_set_header Host $host:$server_port; # 指定哪个目录作为根目录, 用于文件的检索 root /home/django/projects/blogs; # 启用Gzip压缩 gzip on; # 对js、css、jpg、png、gif格式的文件启用gzip压缩功能 gzip_types application/javascript text/css image/jpeg image/png image/gif; # 所压缩文件的最小值,小于这个的不会压缩 gzip_min_length 1024; # 使用名为cache_one的对应缓存配置. proxy_cache cache_one; # 对httpcode为200, 206, 301, 302, 304的缓存10天. proxy_cache_valid 200 206 301 302 304 10d; # 定义缓存唯一key, 通过唯一key来进行hash存取. proxy_cache_key $uri # 过期30天, 静态文件不怎么更新, 过期可以设大一点, 如果频繁更新, 则可以设置得小一点. expires 30d; } } 3. Redis配置文件redis.conf # Redis配置文件样例 # Note on units: when memory size is needed, it is possible to specifiy # it in the usual form of 1k 5GB 4M and so forth: # # 1k => 1000 bytes # 1kb => 1024 bytes # 1m => 1000000 bytes # 1mb => 1024*1024 bytes # 1g => 1000000000 bytes # 1gb => 1024*1024*1024 bytes # # units are case insensitive so 1GB 1Gb 1gB are all the same. # Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 # 启用守护进程后,Redis会把pid写到一个pidfile中,在/var/run/redis.pid daemonize no # 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定 pidfile /var/run/redis.pid # 指定Redis监听端口,默认端口为6379 # 如果指定0端口,表示Redis不监听TCP连接 port 6379 # 绑定的主机地址 # 你可以绑定单一接口,如果没有绑定,所有接口都会监听到来的连接 # bind 127.0.0.1 # Specify the path for the unix socket that will be used to listen for # incoming connections. There is no default, so Redis will not listen # on a unix socket when not specified. # # unixsocket /tmp/redis.sock # unixsocketperm 755 # 当客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能 timeout 0 # 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose # debug (很多信息, 对开发/测试比较有用) # verbose (many rarely useful info, but not a mess like the debug level) # notice (moderately verbose, what you want in production probably) # warning (only very important / critical messages are logged) loglevel verbose # 日志记录方式,默认为标准输出,如果配置为redis为守护进程方式运行,而这里又配置为标准输出,则日志将会发送给/dev/null logfile stdout # To enable logging to the system logger, just set 'syslog-enabled' to yes, # and optionally update the other syslog parameters to suit your needs. # syslog-enabled no # Specify the syslog identity. # syslog-ident redis # Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7. # syslog-facility local0 # 设置数据库的数量,默认数据库为0,可以使用select <dbid>命令在连接上指定数据库id # dbid是从0到‘databases’-1的数目 databases 16 ################################ SNAPSHOTTING ################################# # 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合 # Save the DB on disk: # # save <seconds> <changes> # # Will save the DB if both the given number of seconds and the given # number of write operations against the DB occurred. # # 满足以下条件将会同步数据: # 900秒(15分钟)内有1个更改 # 300秒(5分钟)内有10个更改 # 60秒内有10000个更改 # Note: 可以把所有“save”行注释掉,这样就取消同步操作了 save 900 1 save 300 10 save 60 10000 # 指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大 rdbcompression yes # 指定本地数据库文件名,默认值为dump.rdb dbfilename dump.rdb # 工作目录. # 指定本地数据库存放目录,文件名由上一个dbfilename配置项指定 # # Also the Append Only File will be created inside this directory. # # 注意,这里只能指定一个目录,不能指定文件名 dir ./ ################################# REPLICATION ################################# # 主从复制。使用slaveof从 Redis服务器复制一个Redis实例。注意,该配置仅限于当前slave有效 # so for example it is possible to configure the slave to save the DB with a # different interval, or to listen to another port, and so on. # 设置当本机为slav服务时,设置master服务的ip地址及端口,在Redis启动时,它会自动从master进行数据同步 # slaveof <masterip> <masterport> # 当master服务设置了密码保护时,slav服务连接master的密码 # 下文的“requirepass”配置项可以指定密码 # masterauth <master-password> # When a slave lost the connection with the master, or when the replication # is still in progress, the slave can act in two different ways: # # 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will # still reply to client requests, possibly with out of data data, or the # data set may just be empty if this is the first synchronization. # # 2) if slave-serve-stale data is set to 'no' the slave will reply with # an error "SYNC with master in progress" to all the kind of commands # but to INFO and SLAVEOF. # slave-serve-stale-data yes # Slaves send PINGs to server in a predefined interval. It's possible to change # this interval with the repl_ping_slave_period option. The default value is 10 # seconds. # # repl-ping-slave-period 10 # The following option sets a timeout for both Bulk transfer I/O timeout and # master data or ping response timeout. The default value is 60 seconds. # # It is important to make sure that this value is greater than the value # specified for repl-ping-slave-period otherwise a timeout will be detected # every time there is low traffic between the master and the slave. # # repl-timeout 60 ################################## SECURITY ################################### # Warning: since Redis is pretty fast an outside user can try up to # 150k passwords per second against a good box. This means that you should # use a very strong password otherwise it will be very easy to break. # 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过auth <password>命令提供密码,默认关闭 requirepass root # Command renaming. # # It is possilbe to change the name of dangerous commands in a shared # environment. For instance the CONFIG command may be renamed into something # of hard to guess so that it will be still available for internal-use # tools but not available for general clients. # # Example: # # rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 # # It is also possilbe to completely kill a command renaming it into # an empty string: # # rename-command CONFIG "" ################################### LIMITS #################################### # 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数, # 如果设置maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max Number of clients reached错误信息 # maxclients 128 # Don't use more memory than the specified amount of bytes. # When the memory limit is reached Redis will try to remove keys with an # EXPIRE set. It will try to start freeing keys that are going to expire # in little time and preserve keys with a longer time to live. # Redis will also try to remove objects from free lists if possible. # # If all this fails, Redis will start to reply with errors to commands # that will use more memory, like SET, LPUSH, and so on, and will continue # to reply to most read-only commands like GET. # # WARNING: maxmemory can be a good idea mainly if you want to use Redis as a # 'state' server or cache, not as a real DB. When Redis is used as a real # database the memory usage will grow over the weeks, it will be obvious if # it is going to use too much memory in the long run, and you'll have the time # to upgrade. With maxmemory after the limit is reached you'll start to get # errors for write operations, and this may even lead to DB inconsistency. # 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key, # 当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。 # Redis新的vm机制,会把Key存放内存,Value会存放在swap区 # maxmemory <bytes> # MAXMEMORY POLICY: how Redis will select what to remove when maxmemory # is reached? You can select among five behavior: # # volatile-lru -> remove the key with an expire set using an LRU algorithm # allkeys-lru -> remove any key accordingly to the LRU algorithm # volatile-random -> remove a random key with an expire set # allkeys->random -> remove a random key, any key # volatile-ttl -> remove the key with the nearest expire time (minor TTL) # noeviction -> don't expire at all, just return an error on write operations # # Note: with all the kind of policies, Redis will return an error on write # operations, when there are not suitable keys for eviction. # # At the date of writing this commands are: set setnx setex append # incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd # sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby # zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby # getset mset msetnx exec sort # # The default is: # # maxmemory-policy volatile-lru # LRU and minimal TTL algorithms are not precise algorithms but approximated # algorithms (in order to save memory), so you can select as well the sample # size to check. For instance for default Redis will check three keys and # pick the one that was used less recently, you can change the sample size # using the following configuration directive. # # maxmemory-samples 3 ############################## APPEND ONLY MODE ############################### # # Note that you can have both the async dumps and the append only file if you # like (you have to comment the "save" statements above to disable the dumps). # Still if append only mode is enabled Redis will load the data from the # log file at startup ignoring the dump.rdb file. # 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。 # 因为redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no # IMPORTANT: Check the BGREWRITEAOF to check how to rewrite the append # log file in background when it gets too big. appendonly no # 指定更新日志文件名,默认为appendonly.aof # appendfilename appendonly.aof # The fsync() call tells the Operating System to actually write data on disk # instead to wait for more data in the output buffer. Some OS will really flush # data on disk, some other OS will just try to do it ASAP. # 指定更新日志条件,共有3个可选值: # no:表示等操作系统进行数据缓存同步到磁盘(快) # always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全) # everysec:表示每秒同步一次(折衷,默认值) appendfsync everysec # appendfsync no # When the AOF fsync policy is set to always or everysec, and a background # saving process (a background save or AOF log background rewriting) is # performing a lot of I/O against the disk, in some Linux configurations # Redis may block too long on the fsync() call. Note that there is no fix for # this currently, as even performing fsync in a different thread will block # our synchronous write(2) call. # # In order to mitigate this problem it's possible to use the following option # that will prevent fsync() from being called in the main process while a # BGSAVE or BGREWRITEAOF is in progress. # # This means that while another child is saving the durability of Redis is # the same as "appendfsync none", that in pratical terms means that it is # possible to lost up to 30 seconds of log in the worst scenario (with the # default Linux settings). # # If you have latency problems turn this to "yes". Otherwise leave it as # "no" that is the safest pick from the point of view of durability. no-appendfsync-on-rewrite no # Automatic rewrite of the append only file. # Redis is able to automatically rewrite the log file implicitly calling # BGREWRITEAOF when the AOF log size will growth by the specified percentage. # # This is how it works: Redis remembers the size of the AOF file after the # latest rewrite (or if no rewrite happened since the restart, the size of # the AOF at startup is used). # # This base size is compared to the current size. If the current size is # bigger than the specified percentage, the rewrite is triggered. Also # you need to specify a minimal size for the AOF file to be rewritten, this # is useful to avoid rewriting the AOF file even if the percentage increase # is reached but it is still pretty small. # # Specify a precentage of zero in order to disable the automatic AOF # rewrite feature. auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb ################################## SLOW LOG ################################### # The Redis Slow Log is a system to log queries that exceeded a specified # execution time. The execution time does not include the I/O operations # like talking with the client, sending the reply and so forth, # but just the time needed to actually execute the command (this is the only # stage of command execution where the thread is blocked and can not serve # other requests in the meantime). # # You can configure the slow log with two parameters: one tells Redis # what is the execution time, in microseconds, to exceed in order for the # command to get logged, and the other parameter is the length of the # slow log. When a new command is logged the oldest one is removed from the # queue of logged commands. # The following time is expressed in microseconds, so 1000000 is equivalent # to one second. Note that a negative number disables the slow log, while # a value of zero forces the logging of every command. slowlog-log-slower-than 10000 # There is no limit to this length. Just be aware that it will consume memory. # You can reclaim memory used by the slow log with SLOWLOG RESET. slowlog-max-len 1024 ############################### ADVANCED CONFIG ############################### # Hashes are encoded in a special way (much more memory efficient) when they # have at max a given numer of elements, and the biggest element does not # exceed a given threshold. You can configure this limits with the following # configuration directives. # 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法 # hash-max-zipmap-entries 512 # hash-max-zipmap-value 64 # Similarly to hashes, small lists are also encoded in a special way in order # to save a lot of space. The special representation is only used when # you are under the following limits: list-max-ziplist-entries 512 list-max-ziplist-value 64 # Sets have a special encoding in just one case: when a set is composed # of just strings that happens to be integers in radix 10 in the range # of 64 bit signed integers. # The following configuration setting sets the limit in the size of the # set in order to use this special memory saving encoding. set-max-intset-entries 512 # Similarly to hashes and lists, sorted sets are also specially encoded in # order to save a lot of space. This encoding is only used when the length and # elements of a sorted set are below the following limits: zset-max-ziplist-entries 128 zset-max-ziplist-value 64 # Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in # order to help rehashing the main Redis hash table (the one mapping top-level # keys to values). The hash table implementation redis uses (see dict.c) # performs a lazy rehashing: the more operation you run into an hash table # that is rhashing, the more rehashing "steps" are performed, so if the # server is idle the rehashing is never complete and some more memory is used # by the hash table. # # The default is to use this millisecond 10 times every second in order to # active rehashing the main dictionaries, freeing memory when possible. # # If unsure: # use "activerehashing no" if you have hard latency requirements and it is # not a good thing in your environment that Redis can reply form time to time # to queries with 2 milliseconds delay. # 指定是否激活重置哈希,默认为开启 activerehashing yes ################################## INCLUDES ################################### # 指定包含其他的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各实例又拥有自己的特定配置文件 # include /path/to/local.conf # include /path/to/other.conf 4. MySQL中my.cnf的配置 [client] port = 3306 socket = /tmp/mysql.sock [mysqld] port = 3306 socket = /tmp/mysql.sock basedir = /usr/local/mysql datadir = /data/mysql pid-file = /data/mysql/mysql.pid user = mysql bind-address = 0.0.0.0 server-id = 1 #表示是本机的序号为1,一般来讲就是master的意思 skip-name-resolve # 禁止MySQL对外部连接进行DNS解析,使用这一选项可以消除MySQL进行DNS解析的时间。但需要注意,如果开启该选项, # 则所有远程主机连接授权都要使用IP地址方式,否则MySQL将无法正常处理连接请求 #skip-networking back_log = 600 # MySQL能有的连接数量。当主要MySQL线程在一个很短时间内得到非常多的连接请求,这就起作用, # 然后主线程花些时间(尽管很短)检查连接并且启动一个新线程。back_log值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。 # 如果期望在一个短时间内有很多连接,你需要增加它。也就是说,如果MySQL的连接数据达到max_connections时,新来的请求将会被存在堆栈中, # 以等待某一连接释放资源,该堆栈的数量即back_log,如果等待连接的数量超过back_log,将不被授予连接资源。 # 另外,这值(back_log)限于您的操作系统对到来的TCP/IP连接的侦听队列的大小。 # 你的操作系统在这个队列大小上有它自己的限制(可以检查你的OS文档找出这个变量的最大值),试图设定back_log高于你的操作系统的限制将是无效的。 max_connections = 1000 # MySQL的最大连接数,如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,介于MySQL会为每个连接提供连接缓冲区,就会开销越多的内存,所以要适当调整该值,不能盲目提高设值。可以过'conn%'通配符查看当前状态的连接数量,以定夺该值的大小。 max_connect_errors = 6000 # 对于同一主机,如果有超出该参数值个数的中断错误连接,则该主机将被禁止连接。如需对该主机进行解禁,执行:FLUSH HOST。 open_files_limit = 65535 # MySQL打开的文件描述符限制,默认最小1024;当open_files_limit没有被配置的时候,比较max_connections*5和ulimit -n的值,哪个大用哪个, # 当open_file_limit被配置的时候,比较open_files_limit和max_connections*5的值,哪个大用哪个。 table_open_cache = 128 # MySQL每打开一个表,都会读入一些数据到table_open_cache缓存中,当MySQL在这个缓存中找不到相应信息时,才会去磁盘上读取。默认值64 # 假定系统有200个并发连接,则需将此参数设置为200*N(N为每个连接所需的文件描述符数目); # 当把table_open_cache设置为很大时,如果系统处理不了那么多文件描述符,那么就会出现客户端失效,连接不上 max_allowed_packet = 4M # 接受的数据包大小;增加该变量的值十分安全,这是因为仅当需要时才会分配额外内存。例如,仅当你发出长查询或MySQLd必须返回大的结果行时MySQLd才会分配更多内存。 # 该变量之所以取较小默认值是一种预防措施,以捕获客户端和服务器之间的错误信息包,并确保不会因偶然使用大的信息包而导致内存溢出。 binlog_cache_size = 1M # 一个事务,在没有提交的时候,产生的日志,记录到Cache中;等到事务提交需要提交的时候,则把日志持久化到磁盘。默认binlog_cache_size大小32K max_heap_table_size = 8M # 定义了用户可以创建的内存表(memory table)的大小。这个值用来计算内存表的最大行数值。这个变量支持动态改变 tmp_table_size = 16M # MySQL的heap(堆积)表缓冲大小。所有联合在一个DML指令内完成,并且大多数联合甚至可以不用临时表即可以完成。 # 大多数临时表是基于内存的(HEAP)表。具有大的记录长度的临时表 (所有列的长度的和)或包含BLOB列的表存储在硬盘上。 # 如果某个内部heap(堆积)表大小超过tmp_table_size,MySQL可以根据需要自动将内存中的heap表改为基于硬盘的MyISAM表。还可以通过设置tmp_table_size选项来增加临时表的大小。也就是说,如果调高该值,MySQL同时将增加heap表的大小,可达到提高联接查询速度的效果 read_buffer_size = 2M # MySQL读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySQL会为它分配一段内存缓冲区。read_buffer_size变量控制这一缓冲区的大小。 # 如果对表的顺序扫描请求非常频繁,并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能 read_rnd_buffer_size = 8M # MySQL的随机读缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时, # MySQL会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要排序大量数据,可适当调高该值。但MySQL会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大 sort_buffer_size = 8M # MySQL执行排序使用的缓冲大小。如果想要增加ORDER BY的速度,首先看是否可以让MySQL使用索引而不是额外的排序阶段。 # 如果不能,可以尝试增加sort_buffer_size变量的大小 join_buffer_size = 8M # 联合查询操作所能使用的缓冲区大小,和sort_buffer_size一样,该参数对应的分配内存也是每连接独享 thread_cache_size = 8 # 这个值(默认8)表示可以重新利用保存在缓存中线程的数量,当断开连接时如果缓存中还有空间,那么客户端的线程将被放到缓存中, # 如果线程重新被请求,那么请求将从缓存中读取,如果缓存中是空的或者是新的请求,那么这个线程将被重新创建,如果有很多新的线程, # 增加这个值可以改善系统性能.通过比较Connections和Threads_created状态的变量,可以看到这个变量的作用。(–>表示要调整的值) # 根据物理内存设置规则如下: # 1G —> 8 # 2G —> 16 # 3G —> 32 # 大于3G —> 64 query_cache_size = 8M #MySQL的查询缓冲大小(从4.0.1开始,MySQL提供了查询缓冲机制)使用查询缓冲,MySQL将SELECT语句和查询结果存放在缓冲区中, # 今后对于同样的SELECT语句(区分大小写),将直接从缓冲区中读取结果。根据MySQL用户手册,使用查询缓冲最多可以达到238%的效率。 # 通过检查状态值'Qcache_%',可以知道query_cache_size设置是否合理:如果Qcache_lowmem_prunes的值非常大,则表明经常出现缓冲不够的情况, # 如果Qcache_hits的值也非常大,则表明查询缓冲使用非常频繁,此时需要增加缓冲大小;如果Qcache_hits的值不大,则表明你的查询重复率很低, # 这种情况下使用查询缓冲反而会影响效率,那么可以考虑不用查询缓冲。此外,在SELECT语句中加入SQL_NO_CACHE可以明确表示不使用查询缓冲 query_cache_limit = 2M #指定单个查询能够使用的缓冲区大小,默认1M key_buffer_size = 4M #指定用于索引的缓冲区大小,增加它可得到更好处理的索引(对所有读和多重写),到你能负担得起那样多。如果你使它太大, # 系统将开始换页并且真的变慢了。对于内存在4GB左右的服务器该参数可设置为384M或512M。通过检查状态值Key_read_requests和Key_reads, # 可以知道key_buffer_size设置是否合理。比例key_reads/key_read_requests应该尽可能的低, # 至少是1:100,1:1000更好(上述状态值可以使用SHOW STATUS LIKE 'key_read%'获得)。注意:该参数值设置的过大反而会是服务器整体效率降低 ft_min_word_len = 4 # 分词词汇最小长度,默认4 transaction_isolation = REPEATABLE-READ # MySQL支持4种事务隔离级别,他们分别是: # READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE. # 如没有指定,MySQL默认采用的是REPEATABLE-READ,ORACLE默认的是READ-COMMITTED log_bin = mysql-bin binlog_format = mixed expire_logs_days = 30 #超过30天的binlog删除 log_error = /data/mysql/mysql-error.log #错误日志路径 slow_query_log = 1 long_query_time = 1 #慢查询时间 超过1秒则为慢查询 slow_query_log_file = /data/mysql/mysql-slow.log performance_schema = 0 explicit_defaults_for_timestamp #lower_case_table_names = 1 #不区分大小写 skip-external-locking #MySQL选项以避免外部锁定。该选项默认开启 default-storage-engine = InnoDB #默认存储引擎 innodb_file_per_table = 1 # InnoDB为独立表空间模式,每个数据库的每个表都会生成一个数据空间 # 独立表空间优点: # 1.每个表都有自已独立的表空间。 # 2.每个表的数据和索引都会存在自已的表空间中。 # 3.可以实现单表在不同的数据库中移动。 # 4.空间可以回收(除drop table操作处,表空不能自已回收) # 缺点: # 单表增加过大,如超过100G # 结论: # 共享表空间在Insert操作上少有优势。其它都没独立表空间表现好。当启用独立表空间时,请合理调整:innodb_open_files innodb_open_files = 500 # 限制Innodb能打开的表的数据,如果库里的表特别多的情况,请增加这个。这个值默认是300 innodb_buffer_pool_size = 64M # InnoDB使用一个缓冲池来保存索引和原始数据, 不像MyISAM. # 这里你设置越大,你在存取表里面数据时所需要的磁盘I/O越少. # 在一个独立使用的数据库服务器上,你可以设置这个变量到服务器物理内存大小的80% # 不要设置过大,否则,由于物理内存的竞争可能导致操作系统的换页颠簸. # 注意在32位系统上你每个进程可能被限制在 2-3.5G 用户层面内存限制, # 所以不要设置的太高. innodb_write_io_threads = 4 innodb_read_io_threads = 4 # innodb使用后台线程处理数据页上的读写 I/O(输入输出)请求,根据你的 CPU 核数来更改,默认是4 # 注:这两个参数不支持动态改变,需要把该参数加入到my.cnf里,修改完后重启MySQL服务,允许值的范围从 1-64 innodb_thread_concurrency = 0 # 默认设置为 0,表示不限制并发数,这里推荐设置为0,更好去发挥CPU多核处理能力,提高并发量 innodb_purge_threads = 1 # InnoDB中的清除操作是一类定期回收无用数据的操作。在之前的几个版本中,清除操作是主线程的一部分,这意味着运行时它可能会堵塞其它的数据库操作。 # 从MySQL5.5.X版本开始,该操作运行于独立的线程中,并支持更多的并发数。用户可通过设置innodb_purge_threads配置参数来选择清除操作是否使用单 # 独线程,默认情况下参数设置为0(不使用单独线程),设置为 1 时表示使用单独的清除线程。建议为1 innodb_flush_log_at_trx_commit = 2 # 0:如果innodb_flush_log_at_trx_commit的值为0,log buffer每秒就会被刷写日志文件到磁盘,提交事务的时候不做任何操作(执行是由mysql的master thread线程来执行的。 # 主线程中每秒会将重做日志缓冲写入磁盘的重做日志文件(REDO LOG)中。不论事务是否已经提交)默认的日志文件是ib_logfile0,ib_logfile1 # 1:当设为默认值1的时候,每次提交事务的时候,都会将log buffer刷写到日志。 # 2:如果设为2,每次提交事务都会写日志,但并不会执行刷的操作。每秒定时会刷到日志文件。要注意的是,并不能保证100%每秒一定都会刷到磁盘,这要取决于进程的调度。 # 每次事务提交的时候将数据写入事务日志,而这里的写入仅是调用了文件系统的写入操作,而文件系统是有 缓存的,所以这个写入并不能保证数据已经写入到物理磁盘 # 默认值1是为了保证完整的ACID。当然,你可以将这个配置项设为1以外的值来换取更高的性能,但是在系统崩溃的时候,你将会丢失1秒的数据。 # 设为0的话,mysqld进程崩溃的时候,就会丢失最后1秒的事务。设为2,只有在操作系统崩溃或者断电的时候才会丢失最后1秒的数据。InnoDB在做恢复的时候会忽略这个值。 # 总结 # 设为1当然是最安全的,但性能页是最差的(相对其他两个参数而言,但不是不能接受)。如果对数据一致性和完整性要求不高,完全可以设为2,如果只最求性能,例如高并发写的日志服务器,设为0来获得更高性能 innodb_log_buffer_size = 2M # 此参数确定些日志文件所用的内存大小,以M为单位。缓冲区更大能提高性能,但意外的故障将会丢失数据。MySQL开发人员建议设置为1-8M之间 innodb_log_file_size = 32M # 此参数确定数据日志文件的大小,更大的设置可以提高性能,但也会增加恢复故障数据库所需的时间 innodb_log_files_in_group = 3 # 为提高性能,MySQL可以以循环方式将日志文件写到多个文件。推荐设置为3 innodb_max_dirty_pages_pct = 90 # innodb主线程刷新缓存池中的数据,使脏数据比例小于90% innodb_lock_wait_timeout = 120 # InnoDB事务在被回滚之前可以等待一个锁定的超时秒数。InnoDB在它自己的锁定表中自动检测事务死锁并且回滚事务。InnoDB用LOCK TABLES语句注意到锁定设置。默认值是50秒 bulk_insert_buffer_size = 8M # 批量插入缓存大小, 这个参数是针对MyISAM存储引擎来说的。适用于在一次性插入100-1000+条记录时, 提高效率。默认值是8M。可以针对数据量的大小,翻倍增加。 myisam_sort_buffer_size = 8M # MyISAM设置恢复表之时使用的缓冲区的尺寸,当在REPAIR TABLE或用CREATE INDEX创建索引或ALTER TABLE过程中排序 MyISAM索引分配的缓冲区 myisam_max_sort_file_size = 10G # 如果临时文件会变得超过索引,不要使用快速排序索引方法来创建一个索引。注释:这个参数以字节的形式给出 myisam_repair_threads = 1 # 如果该值大于1,在Repair by sorting过程中并行创建MyISAM表索引(每个索引在自己的线程内) interactive_timeout = 28800 # 服务器关闭交互式连接前等待活动的秒数。交互式客户端定义为在mysql_real_connect()中使用CLIENT_INTERACTIVE选项的客户端。默认值:28800秒(8小时) wait_timeout = 28800 # 服务器关闭非交互连接之前等待活动的秒数。在线程启动时,根据全局wait_timeout值或全局interactive_timeout值初始化会话wait_timeout值, # 取决于客户端类型(由mysql_real_connect()的连接选项CLIENT_INTERACTIVE定义)。参数默认值:28800秒(8小时) # MySQL服务器所支持的最大连接数是有上限的,因为每个连接的建立都会消耗内存,因此我们希望客户端在连接到MySQL Server处理完相应的操作后, # 应该断开连接并释放占用的内存。如果你的MySQL Server有大量的闲置连接,他们不仅会白白消耗内存,而且如果连接一直在累加而不断开, # 最终肯定会达到MySQL Server的连接上限数,这会报'too many connections'的错误。对于wait_timeout的值设定,应该根据系统的运行情况来判断。 # 在系统运行一段时间后,可以通过show processlist命令查看当前系统的连接状态,如果发现有大量的sleep状态的连接进程,则说明该参数设置的过大, # 可以进行适当的调整小些。要同时设置interactive_timeout和wait_timeout才会生效。 [mysqldump] quick max_allowed_packet = 16M #服务器发送和接受的最大包长度 [myisamchk] key_buffer_size = 8M sort_buffer_size = 8M read_buffer = 4M write_buffer = 4M 5. log4j的log4j.properties # 日志级别(由低到高): # ALL 打开所有日志记录 # DEBUG 调试信息 # INFO 运行信息 # WARN 警告信息,有潜在错误 # ERROR 错误信息,但不影响程序运行 # FATAL 严重信息,会导致程序退出 # OFF 关闭所有日志记录 # 日志的输出方式: # org.apache.log4j.ConsoleAppender(控制台) # org.apache.log4j.FileAppender(文件) # org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件) # org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件) # org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方) # 日志的输出格式: # org.apache.log4j.HTMLLayout(以HTML表格形式布局) # org.apache.log4j.PatternLayout(可以灵活地指定布局模式) # org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串) # org.apache.log4j.TTCCLayout(包含日志产生的时间,线程,类别等信息) # 灵活指定日志输出格式: # %c: 输出所属的类目,通常就是所在类的全名 # %d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如: %d{yyyy-MM-dd HH:mm:ss} 输出类似:2002-10-18 22:10:28 # %l: 输出日志事件的发生位置,包括类目名,发生的线程,在代码中的行数.举例: Testlog4.main(TestLog4.java:10) # %m: 输出代码中指定的消息 # %n: 输出一个回车换行符,Windows平台为"/r/n",Unix平台为"/n" # %p: 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL # %r: 输出自应用启动到输出该log信息耗费的毫秒数 # %t: 输出产生该日志事件的线程名 # 将所有包的日志级别设为INFO(输出INFO及以上级别日志) # 为这些日志配置4种日志输出并命名为: console,info,warn,error(这些名字随便取) log4j.rootLogger=INFO,console,info,warn,error # 将org与com.alibaba包的日志级别设为OFF(关闭所有日志记录) log4j.logger.org=OFF log4j.logger.com.alibaba=OFF # console # 输出方式为: 控制台输出 log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.Target=System.out # 输出级别为INFO(包括INFO,WARN,ERROR,FATAL) log4j.appender.console.Threshold=INFO # 输出格式为: 灵活指定格式 log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH:mm:ss}] %l %m %n # info # 输出方式为: 每天产生一个日志文件 log4j.appender.info=org.apache.log4j.DailyRollingFileAppender # 日志文件位置: ${catalina.home}/logs/paulandcode/base/info.log(${catalina.home}指: D:/Java/apache-tomcat-9.0.0) log4j.appender.info.File=${catalina.home}/logs/paulandcode/base/info.log # 每日生成的日志文件命名方式: info.log.2017-05-24 log4j.appender.info.append=true log4j.appender.info.datePattern='.'yyyy-MM-dd log4j.appender.info.Threshold=INFO log4j.appender.info.layout=org.apache.log4j.PatternLayout log4j.appender.info.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH:mm:ss}] %l %m %n # warn log4j.appender.warn=org.apache.log4j.DailyRollingFileAppender log4j.appender.warn.File=${catalina.home}/logs/paulandcode/base/warn.log log4j.appender.warn.append=true log4j.appender.warn.datePattern='.'yyyy-MM-dd log4j.appender.warn.Threshold=WARN log4j.appender.warn.layout=org.apache.log4j.PatternLayout log4j.appender.warn.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH:mm:ss}] %l %m %n # error log4j.appender.error=org.apache.log4j.DailyRollingFileAppender log4j.appender.error.File=${catalina.home}/logs/paulandcode/base/error.log log4j.appender.error.append=true log4j.appender.error.datePattern='.'yyyy-MM-dd log4j.appender.error.Threshold=ERROR log4j.appender.error.layout=org.apache.log4j.PatternLayout log4j.appender.error.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH:mm:ss}] %l %m %n # slowsql log4j.logger.com.alibaba.druid.filter.stat.StatFilter=ERROR,slowsql log4j.appender.slowsql=org.apache.log4j.DailyRollingFileAppender log4j.appender.slowsql.File=${catalina.home}/logs/paulandcode/base/slow_sql.log log4j.appender.slowsql.append=true log4j.appender.slowsql.datePattern='.'yyyy-MM-dd log4j.appender.slowsql.layout=org.apache.log4j.PatternLayout log4j.appender.slowsql.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] %m %n # sql # 将com.paulandcode.dao包下的日志级别设为DEBUG # 为这些日志配置1种日志输出并命名为:sql log4j.logger.com.paulandcode.dao=DEBUG,sql log4j.appender.sql=org.apache.log4j.ConsoleAppender log4j.appender.sql.Target=System.out log4j.appender.sql.layout=org.apache.log4j.PatternLayout log4j.appender.sql.layout.ConversionPattern=%m %n 6. logback的logback-spring.xml <?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 说明: 1、日志级别及文件 日志记录采用分级记录,级别与日志文件名相对应,不同级别的日志信息记录到不同的日志文件中 例如:error级别记录到log_error_xxx.log或log_error.log(该文件为当前记录的日志文件),而log_error_xxx.log为归档日志, 日志文件按日期记录,同一天内,若日志文件大小等于或大于2M,则按0、1、2...顺序分别命名 例如log-level-2013-12-21.0.log 其它级别的日志也是如此。 2、文件路径 若开发、测试用,在Eclipse中运行项目,则到Eclipse的安装路径查找logs文件夹,以相对路径../logs。 若部署到Tomcat下,则在Tomcat下的logs文件中 3、Appender FILEERROR对应error级别,文件名以log-error-xxx.log形式命名 FILEWARN对应warn级别,文件名以log-warn-xxx.log形式命名 FILEINFO对应info级别,文件名以log-info-xxx.log形式命名 FILEDEBUG对应debug级别,文件名以log-debug-xxx.log形式命名 stdout将日志信息输出到控制上,为方便开发测试使用 --> <contextName>SpringBootDemo</contextName> <property name="LOG_PATH" value="C:/log/spring-boot" /> <!--设置系统日志目录--> <property name="APPDIR" value="getdatacenter-fz" /> <logger name="org.springframework" level="WARN" /> <logger name="com.paulandcode.modules.jq.dao" level="DEBUG" /> <logger name="com.paulandcode.modules.yw.dao" level="DEBUG" /> <!-- 日志记录器,日期滚动记录 --> <appender name="FILEERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文件的路径及文件名 --> <file>${LOG_PATH}/${APPDIR}/log_error.log</file> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。 而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 --> <fileNamePattern>${LOG_PATH}/${APPDIR}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始, 命名日志文件,例如log-error-2013-12-21.0.log --> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>2MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <!-- 追加方式记录日志 --> <append>true</append> <!-- 日志文件的格式 --> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern> <charset>utf-8</charset> </encoder> <!-- 此日志文件只记录info级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>error</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 日志记录器,日期滚动记录 --> <appender name="FILEWARN" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文件的路径及文件名 --> <file>${LOG_PATH}/${APPDIR}/log_warn.log</file> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。 而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 --> <fileNamePattern>${LOG_PATH}/${APPDIR}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始, 命名日志文件,例如log-error-2013-12-21.0.log --> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>2MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <!-- 追加方式记录日志 --> <append>true</append> <!-- 日志文件的格式 --> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern> <charset>utf-8</charset> </encoder> <!-- 此日志文件只记录info级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>warn</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 日志记录器,日期滚动记录 --> <appender name="FILEINFO" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文件的路径及文件名 --> <file>${LOG_PATH}/${APPDIR}/log_info.log</file> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。 而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 --> <fileNamePattern>${LOG_PATH}/${APPDIR}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始, 命名日志文件,例如log-error-2013-12-21.0.log --> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>2MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <!-- 追加方式记录日志 --> <append>true</append> <!-- 日志文件的格式 --> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern> <charset>utf-8</charset> </encoder> <!-- 此日志文件只记录info级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>info</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!--encoder 默认配置为PatternLayoutEncoder--> <encoder> <pattern>%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) === %highlight(%-5level) === %yellow(%logger[%-3L]) === %blue(%msg%n)</pattern> <charset>utf-8</charset> </encoder> <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息--> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>debug</level> </filter> </appender> <!-- 生产环境下,将此级别配置为适合的级别,以免日志文件太多或影响程序性能 --> <root level="INFO"> <appender-ref ref="FILEERROR" /> <appender-ref ref="FILEWARN" /> <appender-ref ref="FILEINFO" /> <!-- 生产环境将请stdout,testfile去掉 --> <appender-ref ref="STDOUT" /> </root> </configuration>
001.gui与tui gui, 完全的图形界面. tui, 终端下的图形界面. 002.补全命令 输入前缀, 按一次Tab. 若前缀不唯一, 按2次Tab, 出现相关命令列表. 003.RHEL7.2实现上网功能 1.固定的可用联网IP地址 2.关闭防火墙 3.关闭selinux 4.光盘自动挂载 5.配置好本地yum源 004.linux系统安装分区(标准分区) 1.boot分区:引导分区(启动系统用的), grub(引导器), 内核文件 200M 2.swap分区:内存扩展分区, 一般最多8G或16G 1000M 3./ 根:所有文件的根 10G 4.sda:linux下的第一个磁盘 5.RHEL7使用xfs文件系统, RHEL6使用ext4文件系统, Win7/10使用NTFS文件系统 005.手动配置以太网_IPv4设置 1.ip地址:192.168.0.71(网段192.168一样, 且是没用过的ip) 2.子网掩码:24 3.网关:192.168.0.1 4.DNS服务器:8.8.8.8(或114.114.114.114) 006.ubuntu第一次切换到root用户失败 1.为root设置一个root密码 sudo passwd root // 之后会提示要输入root用户的密码, 连续输入root密码 2.使用 su,并按照提示输入root密码, 就可以在终端中切换成超级管理员用户身份了! 3.设置后,以后就可以直接root登录了 007.ubuntu安装yum 1.安装了build-essential: apt-get install build-essential 2.安装yum: apt-get install yum 008.Xshell由于权限问题无法上传文件到linux 给lunux的文件夹设置权限, 例: 给/usr下的java文件夹添加上传权限 chmod -R 777 /usr/java // -R表示包括子文件夹 添加权限后,在/usr目录下输入: ll // 显示/usr/java这一个文件夹drwxrwxrwx(之前为drwxr-xr-x),并且有绿色阴影 Ubuntu chmod 命令可以用来修改文件或文件夹的读写权限, 命令有两种使用方式: (1)chmod [ u / g / o / a ] [ + / - / = ] [ r / w / x ] file, 其中: u表示User, 是文件的所有者 g表示跟User同Group的用户 o表示Other, 即其他用户 a表示ALL, 所有用户 +表示增加权限 -表示取消权限 =表示取消之前的权限, 并给予唯一的权限 r表示Read, 即读文件 w表示Write, 即写文件 x表示运行文件 file表示文件的路径, 如ubandy-rest/job/views.py For example: chmod u+rw ubandy-rest/job/views.py 2)chmod [xyz] file 其中, x, y, z分别表示数字(最大不超过7), 并分别对应User、Group、Other x, y, z的值由r(r=4), w ( w=2 ), x ( x=1 )来确定 For example:chmod 765 ubandy-rest/authentication/models.py 当然, 你也可以使用通配符 ‘*’, 来设置当前路径下的所有文件的权限 For example: 假如, 当前你的路径下有文件:1.txt, 2.html, 3.py 使用命令:chmod 777 * 可以同时设置上述三个文件的权限为rwx 如果你要修改整个文件夹的权限, 比如你有一个文件夹WhoJoy, 你想修改这个文件夹(包括内部的所有文件)的权限, 那么 可以使用命令:chmod -R 777 WhoJoy/ 其中:-R表示以递归整个文件夹中的子文件 009.ubuntu中apt命令是什么的缩写 the Advanced Packaging Tool 010.Xshell命令行的锁定/解除 Ctrl + q 011.Xshell无法连接到虚拟机,可能原因 1.防火墙未打开22端口 2.未安装openssh-server 3.虚拟机无法联网 012.ubuntu标准磁盘分区:21.5GB primary /boot 2.0GB f ext4 primary swap 2.5GB f swap primary /home 7.0GB f ext4 logical / 10.0GB f ext4 013.ubuntu查看所有组和用户 cat /etc/group sudo cat /etc/shadow 014.查看ip网址 https://ip.cn 或者 https://ipinfo.io 015.ubuntu下载ping和ifconfig命令 apt install iputils-ping apt install net-tools 016.ubuntu16.04关闭/开启mysql开机启动 // 禁止启动 sudo systemctl disable mysql # 开机启动 sudo systemctl enable mysql 017.查看一个目录下所有文件的数量(包括子目录下的文件,只算文件,不算目录) ls -lR|grep "^-"|wc -l 018.ubuntu设置mysql不区分大小写 // 在/etc/mysql/mysql.conf.d/mysqld.cnf文件中加一行代码: lower_case_table_names=1 019.关机 init 0 020.虚拟机切换到主机 Ctrl + Alt 021.清屏 Ctrl + l 022.取消某一操作 Ctrl + c 023.虚拟机BIOS设置 开机按F2(或虚拟机_电源_打开电源进入固件) 024.查看ip ifconfig 025.编辑文件 vim 026.保存退出 :wq 027.不保存退出 :q! 028.撤销 Esc + u 029.进入插入模式 i 030.复制粘贴 插入模式下选中一段文本,按下鼠标滚轮 031.重启 reboot(或者sudo shutdown -r now) 032.查看当前登录用户 whoami 033.切换用户 su - root(用户名) 034.进入全屏 VMware进入全屏Ctrl + Alt + Enter Xshell进入全屏Alt + Enter 035.创建新的文件 touch a.txt 036.复制一个文件夹下所有文件(包括子文件夹)到另一个文件夹下: cp -r /fangjian/tomcat8_new/webapps/ROOT/* /fangjian/bak/oa_20170905_test/ROOT 037.删除一个文件夹下所有文件(包括子文件夹) rm -rf /fangjian/bak/oa_20170905_test/* // 不加/*则删父文件夹 038.查看Linux是32位还是64位 sudo uname -m // i686表示是32位,x86_64表示是64位 039.解压压缩文件 tar -zxvf test.tar.gz 040.创建文件夹 mkdir java 041.为过长的目录建立一个链接 ln -s /usr/java/jdk1.8.0_60/ /usr/jdk 042.查看某进程名的PID ps -ef | grep java 043.根据端口号查看该端口号被谁占用 lsof -i:8080 // 若命令用不了,则需: yum -y install lsof或者: netstat -apn | grep 8080 044.根据进程PID查看该进程占用的端口号 netstat -nap | grep 2703 // 若命令用不了,则需: yum -y install net-tools 045.根据进程PID杀掉该进程 kill -9 2703 046.纯文本形式访问网址 elinks -dump http://www.baidu.com // 若命令用不了,则需: yum -y install elinks 047.RHEL7查看已启动的服务列表 systemctl list-unit-files|grep enabled 048.关闭虚拟机 shutdown -h now 049.Xshell锁屏 Ctrl+s 解锁: Ctrl+q 050.登录mysql mysql -h localhost -u root -proot 051.查看jdk安装路径 which java 或者: echo $JAVA_HOME 052.查看tomcat版本 进入tomcat的bin下执行sh version.sh 053.zip压缩文件 zip -r fileName.zip 文件夹名 解压缩: unzip fileName.zip 054.查看ubuntu版本 sudo lsb_release -a 055.复制一个文件夹下所有文件(包括子文件夹的所有文件但不复制目录,不考虑文件重名)到另一个文件夹下: find /home/dailin/ -type f -exec cp {} /home/c1 ; 056.显示所有ufw应用的配置 sudo ufw app list 057.vim快捷键 01.光标跳转到页面第一行: gg02.光标跳转到页面最后一行: Shift + g03.删除光标所在行: dd04.删除光标所在的向下n行: ndd n表示数字 05.清空文本:先执行:gg 再执行:d + (Shift + g)06.复制光标所在的行: yy07.复制光标所在的向下n行: nyy n表示数字08.将已复制的数据粘贴在光标的下一行: 小p表示09.将已复制的数据粘贴在光标的上一行: 大P10.撤销上一步操作: u (相当于windws的Ctrl + z)11.与u相反, 回到后一步操作: ctrl+r (相当于windws的Ctrl + y)12.重复前一个操作: . 点13.跳转到某一指定行: :12 跳转到第12行14.键入/后, 光标进入VIM底部的命令行, 这时就可以输入以/为开始的/搜索命令,按n搜索下一个,按N搜索上一个 058. 查看文件占用空间大小 du -ah -d 0 -a代表所有文件-h代表加单位-d 0代表: 只深入到第n层目录,若无此属性,则包含所有子目录 059.ubuntu查看磁盘空间 df -h 060.ubuntu永久修改主机名 1、查看主机名在Ubuntu系统中, 快速查看主机名有多种方法:其一, 打开一个GNOME终端窗口, 在命令提示符中可以看到主机名, 主机名通常位于“@”符号后;其二, 在终端窗口中输入命令:hostname或uname –n, 均可以查看到当前主机的主机名. 2、临时修改主机名命令行下运行命令:“hostname 新主机名”其中“新主机名”可以用任何合法字符串来表示. 不过采用这种方式, 新主机名并不保存在系统中, 重启系统后主机名将恢复为原先的主机名称. 例子:hostname ubuntu-temp这样主机名字就临时被修改为ubuntu-temp, 但是终端下不会立即显示生效后的主机名, 重开一个终端窗口(通过ssh连接的终端需要重新连接才可以); 3、永久修改主机名在Ubuntu系统中永久修改主机名也比较简单. 主机名存放在/etc/hostname文件中, 修改主机名时, 编辑hostname文件, 在文件中输入新的主机名并保存该文件即可. 重启系统后, 参照上面介绍的快速查看主机名的办法来确认主机名有没有修改成功. 值得指出的是, 在其它Linux发行版中, 并非都存在/etc/hostname文件. 如Fedora发行版将主机名存放在/etc/sysconfig/network文件中. 所以, 修改主机名时应注意区分是哪种Linux发行版. 4、/etc/hostname与/etc/hosts的区别/etc/hostname中存放的是主机名, hostname文件的一个例子:paulandcode /etc/hosts存放的是域名与ip的对应关系, 域名与主机名没有任何关系, 你可以为任何一个IP指定任意一个或多个名字, hosts文件的一个例子:(IP地址 hostname aliases) aliases可选127.0.0.1 localhost paulandcode127.0.1.1 v-jiwan-ubuntu 061.linux的bash命令一般存放在/sbin, /bin, /usr/bin,这几个目录中 062.ubuntu 显示相对路径 打开 home/paul/.bashrc 找到(可能有多处): PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' 修改将小写w改为大写W保存 执行source home/paul/.bashrc 063.Ubuntu的add-apt-repository: command not found sudo apt-get install software-properties-common python-software-properties 064.创建用户 adduser paul 创建用户 passwd paul 给已创建的用户testuser设置密码 userdel paul 用户名删除用户 给paul用户增加所有权限: vim /etc/sudoers 在root ALL=(ALL:ALL) ALL这一行的下面增加如下代码: paul ALL=(ALL:ALL) ALL 065.给用户增加sudu权限 1) 进入到root用户下. 2)添加文件的写权限. 也就是输入命令"chmod u+w /etc/sudoers". 3)编辑该文件,找到这一 行:"root ALL=(ALL) ALL"在起下面添加"yourName ALL=(ALL) ALL" 4)撤销文件的写权限. 也就是输入命令"chmod u-w /etc/sudoers" 066.删除除了某几个文件之外的所有文件 例:删除A文件夹下除了a文件夹和b.txt文件的其他所有文件和文件夹 rm -rf A/!(a|b.txt) 不过一般bash中运行后会提示 “-bash: !: event not found ” 可以通过运行shopt -s extgolb来解决. 如下: [root@localhost abc]# rm -f !(a) -bash: !: event not found [root@localhost abc]# shopt -s extglob [root@localhost abc]# rm -f !(a) [root@localhost abc]# ls a 067.linux脚本加入延时等待 默认以秒为单位,以后接时间的单位, 可以以m表示分钟, h表示小时, d表示天数 sleep 5 sleep 0.005 sleep 3m 068.awk -F ':' '{print $1"\t"$3}', 以冒号为分隔符后把第1,3列,以t分隔输出 例: kill掉第一个java进程id netstat -apn |grep java |awk '{print $7}' |xargs |awk -F '/' '{print $1}' |xargs kill -9 069.查看文件夹的目录结构 sudo tree /etc/nginx 070. Linux上的MySQL设置区分大小写 在/etc/mysql/mysql.conf.d/mysqld.cnf中最后一行加入如下代码: lower_case_table_names=1 071.Ubuntu安装MySQL sudo apt update sudo apt install mysql-server mysql-client 072. Linux下使用命令行导入, 导出MySQL数据库 (1) 导出数据库1> 只导出表结构, 格式: mysqldump -u用户名 -p密码 -d 数据库名 > 文件名.sql /usr/local/mysql/bin/mysqldump -uroot -p -d abc > file.sql 若-p后不加密码, 则敲回车后会提示输入密码 2> 导出表结构和数据, 格式: mysqldump -u用户名 -p密码 数据库名 > 文件名.sql /usr/local/mysql/bin/mysqldump -uroot -p abc > file.sql (2) 导入数据库1> 使用MySQL的Bash命令, 格式: mysql -u用户名 -p密码 数据库名 < 文件名.sql mysql -uroot -p abc < file.sql 2> 进入MySQL执行命令a.进入MySQL mysql -uroot -p b.选择数据库 use abc; c.设置数据库编码, 这个很关键, 否则会乱码 set names utf8; d.导入数据 source /home/abc/file.sql; 073. Linux重启后Tomcat自动启动 只需更改一个文件后重启即可: /etc/rc.local在文件结尾加入如下代码 export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export PATH=$JAVA_HOME/bin:$PATH export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export CATALINA_HOME=/home/paul/apache-tomcat-9.0.0.M26 # tomcat自启动 /home/paul/apache-tomcat-9.0.0.M26/bin/startup.sh 074. 虚拟机上的Tomcat无法被主机访问 防火墙原因, 允许访问8080端口: sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent sudo firewall-cmd --reload 如果不使用“--permanent”标记, 把么防火墙规则在重启后会失效. 075. Linux上的MySQL设置区分大小写 在/etc/mysql/mysql.conf.d/mysqld.cnf中最后一行加入如下代码: lower_case_table_names=1 076. Linux虚拟机桥接联网的配置文件 Linux虚拟机桥接联网时需要如下两个配置文件: 1. /etc/resolv.conf nameserver 8.8.8.8 2. /etc/sysconfig/network-scripts/ifcfg-eno16777736 TYPE="Ethernet" BOOTPROTO="static" IPADDR="192.168.0.66" NETWORK="255.255.255.0" GATEWAY="192.168.0.1" DNS1="8.8.8.8" DEFROUTE="yes" PEERDNS="yes" PEERROUTES="yes" IPV4_FAILURE_FATAL="no" IPV6INIT="yes" IPV6_AUTOCONF="yes" IPV6_DEFROUTE="yes" IPV6_PEERDNS="yes" IPV6_PEERROUTES="yes" IPV6_FAILURE_FATAL="no" NAME="eno16777736" UUID="96aa40e3-de9e-4074-b4ad-760d28ae2b66" DEVICE="eno16777736" ONBOOT="yes" 077. 如何Ping固定端口号 1. Windows 需要选择: 控制面板 --> 程序 --> 启动或关闭Windows功能, 在Telnet客户端和Telnet服务端打勾. 被Ping的机器需要服务端, 要Ping的机器需要客户端. 2. Linux若没有自带telnet, 需要安装客户端和服务端 3. 连接命令: telnet 127.0.0.1 8080 注意: IP和端口号之间是空格, 不是冒号.
如果是手机端和pc端需要跳转不同的页面, 则需要在nginx.conf中的location / {}中加入如下代码: if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') { rewrite ^.+ http://127.0.0.1:8080/mobile/$uri; } 其中mobile为手机端的路径标识, 可以自定义修改.
一. jeesite4项目文件夹下有五个文件, 他们通过Maven构成了项目的四个模块, 文件结构如下(去掉其他不相关文件): 其中root为根, 根下包含了四个模块, common(公共模块), modules/core(核心模块), parent(父模块), web(web业务模块)导入项目时, 只需要导入root中的pom.xml即可将项目所有模块导入 二. root中pom.xml部分代码如下: <groupId>com.jeesite</groupId> <artifactId>jeesite-root</artifactId> <version>4.1.3-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>../parent</module> <module>../common</module> <module>../modules/core</module> <module>../web</module> </modules> 打包方式为: pom modules标签中声名了该项目的四个模块(指定模块文件夹的相对路径) 三. parent中pom.xml部分代码如下: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> </parent> <groupId>com.jeesite</groupId> <artifactId>jeesite-parent</artifactId> <version>4.1.3-SNAPSHOT</version> <packaging>pom</packaging> parent标签指定该模块继承自spring boot(Maven中的继承与Java中的继承类似, 作用是复用) 打包方式为: pom 四. common中pom.xml部分代码如下: <parent> <groupId>com.jeesite</groupId> <artifactId>jeesite-parent</artifactId> <version>4.1.3-SNAPSHOT</version> <relativePath>../parent/pom.xml</relativePath> </parent> <artifactId>jeesite-common</artifactId> <packaging>jar</packaging> relativePath指定父项目, 若不写, 默认为"../pom.xml", 若在指定处找不到父项目, 则从本地仓库中寻找, 还找不到则从远程仓库中寻找. 打包方式为jar 五. module/core中pom.xml部分代码如下: <parent> <groupId>com.jeesite</groupId> <artifactId>jeesite-parent</artifactId> <version>4.1.3-SNAPSHOT</version> <relativePath>../../parent/pom.xml</relativePath> </parent> <artifactId>jeesite-module-core</artifactId> <packaging>jar</packaging> 六. web中pom.xml部分代码如下: <parent> <groupId>com.jeesite</groupId> <artifactId>jeesite-parent</artifactId> <version>4.1.3-SNAPSHOT</version> <relativePath>../parent/pom.xml</relativePath> </parent> <artifactId>jeesite-web</artifactId> <packaging>war</packaging> 这里打包方式为war
一. JDK环境变量配置 1. 位置 我的电脑右键 --> 属性 --> 高级系统设置 --> 环境变量 2. 作用域 环境变量窗口中有用户变量和系统变量, 两者的作用域不同, 前者作用域为当前登录用户, 后者作用域为整个计算机. 3. 配置内容 添加如下三个变量, 如果变量已经存在, 则在已有的变量值后面追加即可, 变量值的每一项内容之间要用英文分号隔开. 变量名 变量值 JAVA_HOME D:Javajdk1.8; PATH %JAVA_HOME%bin; CLASSPATH %JAVA_HOME%libtools.jar; 二. Java后台获得客户端IP import com.alibaba.druid.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletRequest; /** * 获取客户端IP地址 * * @author paulandcode * @email paulandcode@gmail.com * @date 2017年3月8日 下午12:57:02 */ public class IPUtils { private static Logger logger = LoggerFactory.getLogger(IPUtils.class); /** * 获取客户端IP地址 * * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址 * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址 */ public static String getIpAddr(HttpServletRequest request) { String ip = null; try { ip = request.getHeader("x-forwarded-for"); if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } } catch (Exception e) { logger.error("IPUtils ERROR ", e); } return ip; } } 三. 无参获取Request和Response import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; /** * * @author paulandcode * @email paulandcode@gmail.com * @date 2017年3月8日 下午12:57:02 */ public class HttpContextUtils { /** * 获取Request */ public static HttpServletRequest getHttpServletRequest() { if(RequestContextHolder.getRequestAttributes()==null){ return null; } return ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); } /** * 获取Response */ public static HttpServletResponse getHttpServletResponse() { if(RequestContextHolder.getRequestAttributes()==null){ return null; } return ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse(); } } 四. Java代码行数统计 该类须放在src/test/java下 import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; /** * * @author paulandcode * @email paulandcode@gmail.com * @date 2017年5月18日 下午13:27:13 */ public class CodeCounter { static long files = 0; static long codeLines = 0; static long commentLines = 0; static long blankLines = 0; static ArrayList<File> fileArray = new ArrayList<File>(); /** * 获得目录下的文件和子目录下的文件 * @param f * @return */ public static ArrayList<File> getFile(File f) { File[] ff = f.listFiles(); for (File child : ff) { if (child.isDirectory()) { getFile(child); } else fileArray.add(child); } return fileArray; } /** * 统计方法 * @param f */ private static void count(File f) { BufferedReader br = null; boolean flag = false; try { br = new BufferedReader(new FileReader(f)); String line = ""; while ((line = br.readLine()) != null) { line = line.trim(); // 除去注释前的空格 if (line.matches("^[ ]*$")) { // 匹配空行 blankLines++; } else if (line.startsWith("//")) { commentLines++; } else if (line.startsWith("/*") && !line.endsWith("*/")) { commentLines++; flag = true; } else if (line.startsWith("/*") && line.endsWith("*/")) { commentLines++; } else if (flag == true) { commentLines++; if (line.endsWith("*/")) { flag = false; } } else { codeLines++; } } files++; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (br != null) { try { br.close(); br = null; } catch (IOException e) { e.printStackTrace(); } } } } /** * 代码行数统计 */ public static void main(String[] args) { String file = CodeCounter.class.getResource("/").getFile(); String path = file.replace("target/test-classes", "src"); ArrayList<File> al = getFile(new File(path)); for (File f : al) { if (f.getName().matches(".*\\.java$")){ // 匹配java格式的文件 count(f); System.out.println(f); } } System.out.println("统计文件:" + files); System.out.println("代码行数:" + codeLines); System.out.println("注释行数:" + commentLines); System.out.println("空白行数:" + blankLines); } } 五. 判断设备类型(PC, 手机等), 浏览器类型(IE, Google等) 1. Maven导包如下 <dependency> <groupId>eu.bitwalker</groupId> <artifactId>UserAgentUtils</artifactId> <version>1.21</version> </dependency> 2. 工具类如下 import javax.servlet.http.HttpServletRequest; import eu.bitwalker.useragentutils.Browser; import eu.bitwalker.useragentutils.DeviceType; import eu.bitwalker.useragentutils.UserAgent; /** * 用户代理字符串识别工具 * * @author paulandcode * @email paulandcode@gmail.com * @date 2017年5月18日 下午13:27:13 */ public class UserAgentUtils { /** * 获取用户代理对象 * * @param request * @return */ public static UserAgent getUserAgent(HttpServletRequest request) { return UserAgent.parseUserAgentString(request.getHeader("User-Agent")); } /** * 获取设备类型 * * @param request * @return */ public static DeviceType getDeviceType(HttpServletRequest request) { return getUserAgent(request).getOperatingSystem().getDeviceType(); } /** * 是否是PC * * @param request * @return */ public static boolean isComputer(HttpServletRequest request) { return DeviceType.COMPUTER.equals(getDeviceType(request)); } /** * 是否是手机 * * @param request * @return */ public static boolean isMobile(HttpServletRequest request) { return DeviceType.MOBILE.equals(getDeviceType(request)); } /** * 是否是平板 * * @param request * @return */ public static boolean isTablet(HttpServletRequest request) { return DeviceType.TABLET.equals(getDeviceType(request)); } /** * 是否是手机和平板 * * @param request * @return */ public static boolean isMobileOrTablet(HttpServletRequest request){ DeviceType deviceType = getDeviceType(request); return DeviceType.MOBILE.equals(deviceType) || DeviceType.TABLET.equals(deviceType); } /** * 获取浏览类型 * * @param request * @return */ public static Browser getBrowser(HttpServletRequest request) { return getUserAgent(request).getBrowser(); } /** * 是否是IE版本且小于等于IE8 * * @param request * @return */ public static boolean isLteIE8(HttpServletRequest request) { Browser browser = getBrowser(request); return Browser.IE5.equals(browser) || Browser.IE6.equals(browser) || Browser.IE7.equals(browser) || Browser.IE8.equals(browser); } } 3. 进行拦截并根据需要进行处理 import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import org.apache.commons.lang3.StringUtils; import com.paulandcode.utils.UserAgentUtils; /** * 根据需要进行拦截, 并做不同处理 * * @author paulandcode * @email paulandcode@gmail.com * @date 2017年5月18日 下午13:27:13 */ public class MobileInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { if (modelAndView != null) { // 如果是手机或平板访问的话,则跳转到手机视图页面。 if (UserAgentUtils.isMobileOrTablet(request) && !StringUtils.startsWithIgnoreCase(modelAndView.getViewName(), "redirect:")) { modelAndView.setViewName("mobile/" + modelAndView.getViewName()); } } } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } } 六. 根据日期生成目录 import java.text.SimpleDateFormat; import java.util.Date; /** * 根据日期生成目录 * * @author paulandcode * @since 2018年7月26日 上午10:33:33 */ public class DirectoryUtils { /** * 生成目录 * return 2018/07/26/1532572300220 */ public static String getDir() { StringBuilder sb = new StringBuilder(""); Date date = new Date(); SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd"); String path = format.format(date); long time = new Date().getTime(); sb.append(path).append("/").append(time); return sb.toString(); } } 七. 根据附件名获得附件类型 1. Maven导包 <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> 2. 工具类 import org.apache.commons.io.FilenameUtils; /** * 附件类型工具类 * * @author paulandcode * @since 2018年7月26日 上午10:57:28 */ public class FileTypeUtils { /** * 根据附件名获得附件类型 * * @param fileName * @return */ public static String getFileType(String fileName) { if (fileName != null && !"".equals(fileName)) { String extension = FilenameUtils.getExtension(fileName); if ("jng".equalsIgnoreCase(extension) || "jpg".equalsIgnoreCase(extension) || "png".equalsIgnoreCase(extension) || "gif".equalsIgnoreCase(extension) || "jpeg".equalsIgnoreCase(extension) || "bmp".equalsIgnoreCase(extension)) { return "IMG"; } else if ("txt".equalsIgnoreCase(extension)) { return "TXT"; } else if ("doc".equalsIgnoreCase(extension) || "docx".equalsIgnoreCase(extension)) { return "DOC"; } else if ("pdf".equalsIgnoreCase(extension)) { return "PDF"; } else if ("xls".equalsIgnoreCase(extension) || "xlsx".equalsIgnoreCase(extension)) { return "XLS"; } else if ("ppt".equalsIgnoreCase(extension) || "pptx".equalsIgnoreCase(extension)) { return "PPT"; } else if ("zip".equalsIgnoreCase(extension)) { return "ZIP"; } else if ("mp3".equalsIgnoreCase(extension)) { return "MP3"; } else if ("mp4".equalsIgnoreCase(extension) || "flv".equalsIgnoreCase(extension) || "avi".equalsIgnoreCase(extension)) { return "AVI"; } else if ("HTML".equalsIgnoreCase(extension)) { return "HTM"; } else if ("VSD".equalsIgnoreCase(extension)) { return "VSD"; } else { return "OTHER"; } } return ""; } } 八. 附件上传下载 1. web.xml中需要加入如下代码 <context-param> <param-name>webAppRootKey</param-name> <param-value>webPath</param-value> </context-param> 2. Java代码如下 import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.multipart.MultipartFile; /** * 附件上传下载 * * @author paulandcode * @since 2018年7月26日 上午11:20:35 */ public class FileUtils { /** * 附件上传 * * @author Paul * @param file * HTML表单上传的附件 * @param subPath * 如: storage/excel * @return 附件最终路径 */ public static String fileUpload(MultipartFile file, String subPath) { // webPath在web.xml中配置, D:\Java\apache-tomcat-9.0.0\webapps\blog\ String basePath = System.getProperty("webPath"); // D:/Java/apache-tomcat-9.0.0/webapps/blog/storage/excel String path = basePath.replaceAll("\\\\", "/") + subPath; // D:/Java/apache-tomcat-9.0.0/webapps/blog/storage/excel/test.xls String finalPath = path + "/" + file.getOriginalFilename(); File dir = new File(path); if (!dir.exists()) { dir.mkdirs(); } try { file.transferTo(new File(finalPath)); } catch (IOException e) { System.out.println("文件: " + file.getOriginalFilename() + "上传失败!"); e.printStackTrace(); } return finalPath; } /** * 附件下载 * * @param request * @param response * @param filePath * 项目根目录下的文件路径, 如: storage/excel/test.xls * @param fileShowName * 下载文件所显示的文件名,需要带后缀名, 如: 测试.xls * @return */ public static boolean excelOutTemplate(HttpServletRequest request, HttpServletResponse response, String filePath, String fileShowName) { // http://127.0.0.1:8080/blog String localPath = request.getServletContext().getRealPath("/"); // http://127.0.0.1:8080/blog/storage/excel/test.xls String finalPath = localPath.endsWith("/") ? (localPath + filePath) : (localPath + "/" + filePath); File file = new File(finalPath); if (file.exists()) { // 防止中文乱码, 设置UTF-8编码 try { response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileShowName, "UTF-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } InputStream in = null; OutputStream out = null; try { in = new FileInputStream(finalPath); out = response.getOutputStream(); int b; while ((b = in.read()) != -1) out.write(b); } catch (IOException e) { e.printStackTrace(); } finally { try { if (in != null) in.close(); if (out != null) out.close(); } catch (IOException e) { e.printStackTrace(); } } } else { System.out.println("服务器文件已经不存在了!"); return false; } return true; } } 九. 获得UUID import java.util.UUID; /** * 获得UUID * * @author paulandcode * @since 2018年7月26日 下午3:00:24 */ public class IDUtils { /** * UUID * @return */ public static String getId() { String id = UUID.randomUUID().toString(); id = id.replace("-", ""); return id; } } 十. 自定义异常类 /** * 自定义异常 * * @author paulandcode * @since 2018年7月26日 下午4:05:28 */ public class RRException extends RuntimeException { private static final long serialVersionUID = 1L; private String msg; private int code = 500; public RRException(String msg) { super(msg); this.msg = msg; } public RRException(String msg, Throwable e) { super(msg, e); this.msg = msg; } public RRException(String msg, int code) { super(msg); this.msg = msg; this.code = code; } public RRException(String msg, int code, Throwable e) { super(msg, e); this.msg = msg; this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } } 十一. 字符串首字母大写 /** * 字符串首字母大写 * * @author paulandcode * @since 2018年7月26日 下午4:29:19 */ public class StringUtils { /** * 字符串首字母大写 */ public static String captureName(String name) { char[] cs=name.toCharArray(); cs[0]-=32; return String.valueOf(cs); } } 十二. List乱序与按照汉字拼音排序 import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Random; /** * List乱序与按照汉字拼音排序 * * @author paulandcode * @since 2018年7月26日 下午3:10:55 */ public class ListUtils { /** * List乱序 * @param sourceList * @return */ public static <V> List<V> randomList(List<V> sourceList) { if (sourceList == null || sourceList.size() == 0) { return sourceList; } List<V> random = new ArrayList<V>(sourceList.size()); do { int index = Math.abs(new Random().nextInt(sourceList.size())); random.add(sourceList.remove(index)); } while (sourceList.size() > 0); return random; } /** * List按照汉字拼音排序, 根据需要重写V的toString()方法 * @param sourceList * @return */ public static <V> List<V> sortList(List<V> sourceList) { if (sourceList == null || sourceList.size() == 0) { return sourceList; } List<V> sort = new ArrayList<V>(sourceList.size()); sort.addAll(sourceList); Collections.sort(sort, new Comparator<V>(){ @Override public int compare(V v0, V v1) { List<String> list = new ArrayList<String>(2); list.add(v0.toString()); list.add(v1.toString()); Collections.sort(list, Collator.getInstance(java.util.Locale.CHINA)); return list.indexOf(v0.toString()) == 0 ? -1 : 1; } }); return sort; } } 十三. Redis工具类 1. properties配置文件 # redis 配置文件 redis.hostName=127.0.0.1 redis.port=6379 redis.timeout=36000 redis.usePool=true redis.maxIdle=6 redis.minEvictableIdleTimeMillis=300000 redis.numTestsPerEvictionRun=3 redis.timeBetweenEvictionRunsMillis=60000 2. Spring添加配置文件 <!-- 配置redis --> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- <property name="maxIdle" value="6"></property> <property name="minEvictableIdleTimeMillis" value="300000"></property> <property name="numTestsPerEvictionRun" value="3"></property> <property name="timeBetweenEvictionRunsMillis" value="60000"></property> --> <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}"></property> <property name="maxIdle" value="${redis.maxIdle}"></property> <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"></property> <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}"></property> </bean> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy"> <property name="poolConfig" ref="jedisPoolConfig"></property> <property name="hostName" value="${redis.hostName}"></property> <property name="port" value="${redis.port}"></property> <property name="timeout" value="${redis.timeout}"></property> <property name="usePool" value="${redis.usePool}"></property> </bean> <bean id="jedisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory"/> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> </bean> 3. Maven依赖 <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.6.2.RELEASE</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> 4. Redis工具类 import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.redis.core.BoundListOperations; import org.springframework.data.redis.core.BoundSetOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; /** * redis缓存存储与获取 * * @author paulandcode * @since 2018年3月8日 下午2:56:46 */ @Service public class RedisCacheUtil { @Autowired @Qualifier("jedisTemplate") public RedisTemplate<Object, Object> redisTemplate; /** * 缓存基本的对象,Integer,String,实体类等 * * @param key * @param value */ public <K, V> void setCacheObject(K key, V value) { redisTemplate.boundValueOps(key).set(value); } /** * 获得缓存的基本对象 * * @param key * @return */ @SuppressWarnings("unchecked") public <K, V> V getCacheObject(K key) { return (V) redisTemplate.boundValueOps(key).get(); } /** * 缓存List * * @param key * @param dataList */ public <K, V> void setCacheList(K key, List<V> dataList) { redisTemplate.delete(key); for (V v : dataList) { redisTemplate.boundListOps(key).rightPush(v); } } /** * 获得缓存的List * * @param key * @return */ @SuppressWarnings("unchecked") public <K, V> List<V> getCacheList(K key) { BoundListOperations<K, V> listOperation = (BoundListOperations<K, V>) redisTemplate.boundListOps(key); return listOperation.range(0, listOperation.size()); } /** * 缓存Set * * @param key * @param dataSet */ @SuppressWarnings("unchecked") public <K, V> void setCacheSet(K key, Set<V> dataSet) { redisTemplate.delete(key); BoundSetOperations<K, V> setOperation = (BoundSetOperations<K, V>) redisTemplate.boundSetOps(key); Iterator<V> it = dataSet.iterator(); while (it.hasNext()) { setOperation.add(it.next()); } } /** * 获得缓存的Set * * @param key * @return */ @SuppressWarnings("unchecked") public <K, V> Set<V> getCacheSet(K key) { return (Set<V>) redisTemplate.boundSetOps(key).members(); } /** * 缓存Map * * @param key * @param dataMap */ public <K, HK, HV> void setCacheMap(K key, Map<HK, HV> dataMap) { redisTemplate.delete(key); redisTemplate.boundHashOps(key).putAll(dataMap); } /** * 获得缓存的Map * * @param key * @return */ @SuppressWarnings("unchecked") public <K, HK, HV> Map<HK, HV> getCacheMap(K key) { return (Map<HK, HV>) redisTemplate.boundHashOps(key).entries(); } /** * 根据key删除对应的缓存 * * @param key, 若key为String, key支持通配符 */ public <K> void deleteByKey(K key) { redisTemplate.delete(redisTemplate.keys(key)); } } 十四. 判断是否是中文 /** * 判断是否是中文. * * @author paulandcode * @since 2018年7月26日 下午4:29:19 */ public class CharUtils { /** * * 判断中文汉字和符号是否是中文. * @param strName 字符串 * @return 字符串是否是中文 */ public static boolean isChinese(String strName) { char[] ch = strName.toCharArray(); for (int i = 0; i < ch.length; i++) { char c = ch[i]; if (isChinese(c)) { return true; } } return false; } /** * * 根据Unicode编码判断中文汉字和符号是否是中文. * @param c 字符 * @return 字符是否是中文 */ private static boolean isChinese(char c) { Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) { return true; } return false; } } 十五. 异常拦截处理 import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.shiro.authz.AuthorizationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import com.alibaba.fastjson.JSON; /** * 异常拦截处理 * * @author paulandcode * @since 2018年7月26日 下午4:15:52 */ @Component public class RRExceptionHandler implements HandlerExceptionResolver { private Logger logger = LoggerFactory.getLogger(getClass()); @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { R r = new R(); try { response.setContentType("application/json;charset=utf-8"); response.setCharacterEncoding("utf-8"); if (ex instanceof RRException) { r.put("code", ((RRException) ex).getCode()); r.put("msg", ((RRException) ex).getMessage()); r.put("tip", ((RRException) ex).getMessage()); }else if(ex instanceof DuplicateKeyException){ r = R.error("数据库中已存在该记录"); }else if(ex instanceof AuthorizationException){ r = R.error("没有权限,请联系管理员授权").put("tip", "没有权限,请联系管理员授权").put("content", null); }else{ r = R.error(); } //记录异常日志 logger.error(ex.getMessage(), ex); String json = JSON.toJSONString(r); response.getWriter().print(json); } catch (Exception e) { logger.error("RRExceptionHandler 异常处理失败", e); e.printStackTrace(); } return new ModelAndView(); } } 十六. Cookie工具类 import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Cookie工具类 * * @author paulandcode * @since 2018年7月26日 下午4:15:52 */ public class CookieUtils { /** * 得到Cookie的值, 不编码 * * @param request * @param cookieName * @return */ public static String getCookieValue(HttpServletRequest request, String cookieName) { return getCookieValue(request, cookieName, false); } /** * 得到Cookie的值 * * @param request * @param cookieName * @return */ public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) { Cookie[] cookieList = request.getCookies(); if (cookieList == null || cookieName == null) { return null; } String retValue = null; try { for (int i = 0; i < cookieList.length; i++) { if (cookieList[i].getName().equals(cookieName)) { if (isDecoder) { retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8"); } else { retValue = cookieList[i].getValue(); } break; } } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return retValue; } /** * 得到Cookie的值 * * @param request * @param cookieName * @return */ public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) { Cookie[] cookieList = request.getCookies(); if (cookieList == null || cookieName == null) { return null; } String retValue = null; try { for (int i = 0; i < cookieList.length; i++) { if (cookieList[i].getName().equals(cookieName)) { retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString); break; } } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return retValue; } /** * * 设置Cookie的值 不设置生效时间默认浏览器关闭即失效,也不编码. * @param request * @param response * @param cookieName * @param cookieValue */ public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue) { setCookie(request, response, cookieName, cookieValue, -1); } /** * * 设置Cookie的值 在指定时间内生效,但不编码. * @param request * @param response * @param cookieName * @param cookieValue * @param cookieMaxage cookie生效的最大秒数 */ public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage) { setCookie(request, response, cookieName, cookieValue, cookieMaxage, false); } /** * * 设置Cookie的值 不设置生效时间,但编码. * @param request * @param response * @param cookieName * @param cookieValue * @param isEncode */ public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, boolean isEncode) { setCookie(request, response, cookieName, cookieValue, -1, isEncode); } /** * * 设置Cookie的值 在指定时间内生效, 编码参数. * @param request * @param response * @param cookieName * @param cookieValue * @param cookieMaxage cookie生效的最大秒数 * @param isEncode 是否编码 */ public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) { doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode); } /** * 设置Cookie的值 在指定时间内生效, 编码参数(指定编码) */ public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage, String encodeString) { doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString); } /** * * 删除Cookie. * @param request * @param response * @param cookieName */ public static void deleteCookie(HttpServletRequest request, HttpServletResponse response, String cookieName) { doSetCookie(request, response, cookieName, "", -1, false); } /** * 设置Cookie的值,并使其在指定时间内生效 * * @param cookieMaxage cookie生效的最大秒数 */ private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) { try { if (cookieValue == null) { cookieValue = ""; } else if (isEncode) { cookieValue = URLEncoder.encode(cookieValue, "utf-8"); } Cookie cookie = new Cookie(cookieName, cookieValue); if (cookieMaxage > 0) cookie.setMaxAge(cookieMaxage); if (null != request) {// 设置域名的cookie String domainName = getDomainName(request); System.out.println(domainName); if (!"localhost".equals(domainName)) { //cookie.setDomain(domainName); } } cookie.setPath("/"); response.addCookie(cookie); } catch (Exception e) { e.printStackTrace(); } } /** * 设置Cookie的值,并使其在指定时间内生效 * * @param cookieMaxage cookie生效的最大秒数 */ private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage, String encodeString) { try { if (cookieValue == null) { cookieValue = ""; } else { cookieValue = URLEncoder.encode(cookieValue, encodeString); } Cookie cookie = new Cookie(cookieName, cookieValue); if (cookieMaxage > 0) cookie.setMaxAge(cookieMaxage); if (null != request) {// 设置域名的cookie String domainName = getDomainName(request); System.out.println(domainName); if (!"localhost".equals(domainName)) { //本地测试的时候不要写.实际发布时在打开 //cookie.setDomain(domainName); } } cookie.setPath("/"); response.addCookie(cookie); } catch (Exception e) { e.printStackTrace(); } } /** * 得到cookie的域名 */ private static final String getDomainName(HttpServletRequest request) { String domainName = null; String serverName = request.getRequestURL().toString(); if (serverName == null || serverName.equals("")) { domainName = ""; } else { final int end = serverName.lastIndexOf("/"); serverName = serverName.substring(0, end); final String[] domains = serverName.split("\\."); int len = domains.length; if (len > 3) { // www.xxx.com.cn domainName = "." + domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1]; } else if (len <= 3 && len > 1) { // xxx.com or xxx.cn domainName = "." + domains[len - 2] + "." + domains[len - 1]; } else { domainName = serverName; } } if (domainName != null && domainName.indexOf(":") > 0) { String[] ary = domainName.split("\\:"); domainName = ary[0]; } return domainName; } } 十七. 日期处理 import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; /** * 日期处理 * * @author paulandcode * @email paulandcode@gmail.com * @date 2017年5月18日 下午13:27:13 */ public class DateUtils { public final static String DATE_PATTERN = "yyyy-MM-dd"; public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; /** * * 默认按照"yyyy-MM-dd"格式化日期. * @param date * @return */ public static String format(Date date) { return format(date, DATE_PATTERN); } /** * * 按照指定的日期格式来格式化日期. * @param date * @param pattern 日期格式 * @return */ public static String format(Date date, String pattern) { if (date != null) { SimpleDateFormat df = new SimpleDateFormat(pattern); return df.format(date); } return null; } /** * 返回给定日期所在月的所有日期集合 * * @param date * @return */ public static List<Date> getAllDatesOfMonth(Date date) { List<Date> list = new ArrayList<Date>(); Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.set(Calendar.DATE, 1); int month = cal.get(Calendar.MONTH); while (cal.get(Calendar.MONTH) == month) { list.add(cal.getTime()); cal.add(Calendar.DATE, 1); } return list; } /** * 判断两个日期是否是同一天 * * @param date1 * @param date2 * @return */ public static boolean isSameDate(Date date1, Date date2) { Calendar cal1 = Calendar.getInstance(); cal1.setTime(date1); Calendar cal2 = Calendar.getInstance(); cal2.setTime(date2); boolean isSameYear = cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR); boolean isSameMonth = isSameYear && cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH); boolean isSameDate = isSameMonth && cal1.get(Calendar.DAY_OF_MONTH) == cal2.get(Calendar.DAY_OF_MONTH); return isSameDate; } /** * * 计算两个日期之间相差多少天 * * @param date1 * @param date2 * @return * @throws ParseException */ public static int getDateSpace(Date date1, Date date2) { Calendar calst = Calendar.getInstance(); Calendar caled = Calendar.getInstance(); calst.setTime(date1); caled.setTime(date2); // 设置时间为0时 calst.set(Calendar.HOUR_OF_DAY, 0); calst.set(Calendar.MINUTE, 0); calst.set(Calendar.SECOND, 0); caled.set(Calendar.HOUR_OF_DAY, 0); caled.set(Calendar.MINUTE, 0); caled.set(Calendar.SECOND, 0); // 得到两个日期相差的天数 return ((int) (caled.getTime().getTime() / 1000) - (int) (calst.getTime().getTime() / 1000)) / 3600 / 24; } } 十八. HttpClient工具类(通过Java后台进行Http访问) 1. Maven导包 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.3.1</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.3.1</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.3.1</version> </dependency> 2. Java代码 import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import javax.net.ssl.SSLContext; import org.apache.http.HttpEntity; import org.apache.http.NameValuePair; import org.apache.http.ParseException; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLContextBuilder; import org.apache.http.conn.ssl.SSLContexts; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.CharsetUtils; import org.apache.http.util.EntityUtils; /** * HttpClient工具类 * * @author paulandcode * @since 2018年7月26日 下午2:35:09 */ public class HttpClientUtils { /** * 成功状态码 */ private static final int SUCCESS = 200; /** * HttpClient连接SSL,需要导入证书的方法 若SSL需要导入信任的证书,使用该方法 * * @param url */ public static void ssl(String url) { CloseableHttpClient httpclient = null; try { KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); FileInputStream instream = new FileInputStream(new File("E:\\tomcat.keystore")); try { // 加载keyStore d:\\tomcat.keystore trustStore.load(instream, "123456".toCharArray()); } catch (CertificateException e) { e.printStackTrace(); } finally { try { instream.close(); } catch (Exception ignore) { } } // 相信自己的CA和所有自签名的证书 SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) .build(); // 只允许使用TLSv1协议 SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); // 创建http请求(get方式) HttpGet httpget = new HttpGet(url); System.out.println("executing request" + httpget.getRequestLine()); CloseableHttpResponse response = httpclient.execute(httpget); try { HttpEntity entity = response.getEntity(); System.out.println("----------------------------------------"); System.out.println(response.getStatusLine()); if (entity != null) { System.out.println("Response content length: " + entity.getContentLength()); System.out.println(EntityUtils.toString(entity)); EntityUtils.consume(entity); } } finally { response.close(); } } catch (ParseException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyStoreException e) { e.printStackTrace(); } finally { if (httpclient != null) { try { httpclient.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 不需要导入证书,SSL信任所有证书,使用该方法 * * @return */ public static CloseableHttpClient createSSLClientDefault() { try { SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { // 信任所有证书 public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }).build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext); return HttpClients.custom().setSSLSocketFactory(sslsf).build(); } catch (KeyManagementException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyStoreException e) { e.printStackTrace(); } return HttpClients.createDefault(); } /** * HttpClient连接SSL,不需要导入证书 信任所有证书,跳过证书验证 * * @param url */ public static void ssl2(String url) { CloseableHttpClient httpclient = null; try { httpclient = createSSLClientDefault(); // 创建http请求(get方式) HttpGet httpget = new HttpGet(url); System.out.println("executing request" + httpget.getRequestLine()); CloseableHttpResponse response = httpclient.execute(httpget); try { HttpEntity entity = response.getEntity(); System.out.println("----------------------------------------"); System.out.println(response.getStatusLine()); if (entity != null) { System.out.println("Response content length: " + entity.getContentLength()); System.out.println(EntityUtils.toString(entity)); EntityUtils.consume(entity); } } finally { response.close(); } } catch (ParseException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (httpclient != null) { try { httpclient.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 关闭HttpClient的客户端和响应 * * @param client 客户端 * @param response 响应 * @return void */ private static void closeClientAndResponse(CloseableHttpClient client, CloseableHttpResponse response) { try { if (response != null) { response.close(); } if (client != null) { client.close(); } } catch (IOException e) { e.printStackTrace(); } } /** * HttpClient模拟浏览器进行Get请求 * * @param url 请求路径, 示例: http://localhost:8080/api/testget * @param params 请求参数 * @return java.util.Map<java.lang.String,java.lang.String> */ public static Map<String, String> doGet(String url, Map<String, String> params) { Map<String, String> result = new HashMap<>(2); result.put("code", "200"); CloseableHttpClient client = null; CloseableHttpResponse response = null; try { //创建一个httpclient对象 client = HttpClients.createDefault(); //创建URIBuilder URIBuilder uri = new URIBuilder(url); //设置参数 if (params != null) { Set<Map.Entry<String, String>> entries = params.entrySet(); for (Map.Entry<String, String> entry : entries) { uri.addParameter(entry.getKey(), entry.getValue()); } } //创建httpGet对象 HttpGet hg = new HttpGet(uri.build()); //设置请求的报文头部的编码 hg.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")); //设置期望服务端返回的编码 hg.setHeader(new BasicHeader("Accept", "application/json;charset=utf-8")); //请求服务 response = client.execute(hg); //获取响应码 int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == SUCCESS) { // 通过EntityUtils的一个工具方法获取返回内容 String resStr = EntityUtils.toString(response.getEntity(), "utf-8"); result.put("data", resStr); } else { result.put("code", statusCode + ""); } } catch (URISyntaxException | IOException e) { e.printStackTrace(); } finally { //关闭response和client closeClientAndResponse(client, response); } return result; } /** * HttpClient模拟浏览器进行Post请求 * * @param url 请求路径, 示例: http://localhost:8080/api/testget * @param params 请求参数 * @return java.util.Map<java.lang.String,java.lang.String> */ public static Map<String, String> doPost(String url, Map<String, String> params){ Map<String, String> result = new HashMap<>(2); result.put("code", "200"); CloseableHttpClient client = null; CloseableHttpResponse response = null; try { //创建一个httpclient对象 client = HttpClients.createDefault(); //创建一个post对象 HttpPost post = new HttpPost(url); //创建一个Entity,模拟表单数据 List<NameValuePair> formList = new ArrayList<>(); //添加表单数据 if (params != null) { Set<Map.Entry<String, String>> entries = params.entrySet(); for (Map.Entry<String, String> entry : entries) { formList.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } } //包装成一个Entity对象 StringEntity entity = new UrlEncodedFormEntity(formList, "utf-8"); //设置请求的内容 post.setEntity(entity); //设置请求的报文头部的编码 post.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")); //设置期望服务端返回的编码 post.setHeader(new BasicHeader("Accept", "application/json;charset=utf-8")); //执行post请求 response = client.execute(post); //获取响应码 int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == SUCCESS) { //获取数据 String resStr = EntityUtils.toString(response.getEntity(), "utf-8"); result.put("data", resStr); } else { result.put("code", statusCode + ""); } } catch (IOException e) { e.printStackTrace(); } finally { //关闭response和client closeClientAndResponse(client, response); } return result; } /** * 上传文件 */ public static void upload(String url) { CloseableHttpClient httpclient = HttpClients.createDefault(); try { HttpPost httppost = new HttpPost(url); FileBody bin = new FileBody(new File("C:\\Users\\zhangwenchao\\Desktop\\jinzhongzi.jpg")); // StringBody name = new StringBody("这个一测试", // ContentType.TEXT_PLAIN); HttpEntity reqEntity = MultipartEntityBuilder.create().setMode(HttpMultipartMode.BROWSER_COMPATIBLE) .addPart("uploadFile", bin).setCharset(CharsetUtils.get("UTF-8")).build(); httppost.setEntity(reqEntity); System.out.println("executing request: " + httppost.getRequestLine()); CloseableHttpResponse response = httpclient.execute(httppost); // httppost = new // HttpPost(response.getLastHeader("location").getValue()); // response = httpclient.execute(httppost); try { System.out.println("----------------------------------------"); System.out.println(response.getStatusLine()); HttpEntity resEntity = response.getEntity(); if (resEntity != null) { // 响应长度 System.out.println("Response content length: " + resEntity.getContentLength()); // 打印响应内容 System.out.println("Response content: " + EntityUtils.toString(resEntity)); } // 销毁 EntityUtils.consume(resEntity); } finally { response.close(); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { httpclient.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 文件下载 */ public static void download(String url) { // 生成一个httpclient对象 CloseableHttpClient httpclient = HttpClients.createDefault(); try { HttpGet httpget = new HttpGet(url); CloseableHttpResponse response = httpclient.execute(httpget); HttpEntity resEntity = response.getEntity(); if (resEntity != null) { // 响应长度 System.out.println("Response content length: " + resEntity.getContentLength()); InputStream in = resEntity.getContent(); String fileName = url.substring(url.lastIndexOf("/")); File file = new File("E:\\" + fileName); try { FileOutputStream fout = new FileOutputStream(file); int l = -1; byte[] tmp = new byte[1024]; while ((l = in.read(tmp)) != -1) { fout.write(tmp, 0, l); // 注意这里如果用OutputStream.write(buff)的话,图片会失真,大家可以试试 } fout.flush(); fout.close(); } finally { // 关闭低层流。 in.close(); } } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { httpclient.close(); } catch (IOException e) { e.printStackTrace(); } } } } 十九. 分页工具类 import java.io.Serializable; import java.util.List; /** * 分页工具类 * * @author paulandcode * @email paulandcode@gmail.com * @date 2017年5月18日 下午13:27:13 */ public class PageUtils implements Serializable { private static final long serialVersionUID = 1L; // 总记录数 private int totalCount; // 每页记录数 private int pageSize; // 总页数 private int totalPage; // 当前页数 private int currPage; // 分页数据 private List<?> list; /** * 新建分页 * @param list 分页数据 * @param totalCount 总记录数 * @param pageSize 每页记录数 * @param currPage 当前页数 */ public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) { this.list = list; this.totalCount = totalCount; this.pageSize = pageSize; this.currPage = currPage; this.totalPage = (int)Math.ceil((double)totalCount/pageSize); } public int getTotalCount() { return totalCount; } public void setTotalCount(int totalCount) { this.totalCount = totalCount; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public int getTotalPage() { return totalPage; } public void setTotalPage(int totalPage) { this.totalPage = totalPage; } public int getCurrPage() { return currPage; } public void setCurrPage(int currPage) { this.currPage = currPage; } public List<?> getList() { return list; } public void setList(List<?> list) { this.list = list; } } 二十. SQL查询工具类 1. SQL过滤 import org.apache.commons.lang.StringUtils; /** * SQL过滤 * * @author paulandcode * @since 2018年7月26日 下午4:29:19 */ public class SQLFilter { /** * * SQL注入过滤. * @param str 待验证的字符串 * @return 过滤后字符串 */ public static String sqlInject(String str){ if(StringUtils.isBlank(str)){ return str; } //去掉'|"|;|\字符 str = StringUtils.replace(str, "'", ""); str = StringUtils.replace(str, "\"", ""); str = StringUtils.replace(str, ";", ""); str = StringUtils.replace(str, "\\", ""); //转换成小写 str = str.toLowerCase(); //非法字符 String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alert", "drop"}; //判断是否包含非法字符 for(String keyword : keywords){ if(str.contains(keyword)){ throw new RuntimeException("包含非法字符"); } } return str; } } 2. SQL查询 import com.paulandcode.utils.SQLFilter; import java.util.LinkedHashMap; import java.util.Map; /** * SQL查询. * * @author paulandcode * @since 2018年7月26日 下午4:29:19 */ public class Q extends LinkedHashMap<String, Object> { private static final long serialVersionUID = 1L; //当前页码 private int page; //每页条数 private int limit; /** * * 构造函数. * @param params */ public Q(Map<String, Object> params){ this.putAll(params); String sidx = ""; String order = ""; if(params.get("page")!=null) { this.page = Integer.parseInt(params.get("page").toString()); } if(params.get("limit")!=null) { this.limit = Integer.parseInt(params.get("limit").toString()); } if(params.get("sidx")!=null) { sidx = params.get("sidx").toString(); } if(params.get("order")!=null) { order = params.get("order").toString(); } //分页参数 this.put("offset", (page - 1) * limit); this.put("page", page); this.put("limit", limit); if(params.get("limit")==null) { this.put("limit", null); } //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险) // sidx为排序字段, 以英文逗号隔开 this.put("sidx", SQLFilter.sqlInject(sidx)); // order为排序方式, DESC或ASC this.put("order", SQLFilter.sqlInject(order)); } /** * * 构造函数. */ public Q() { this.put("page", page); this.put("limit", null); this.put("sidx", ""); this.put("order", ""); } public int getPage() { return page; } public void setPage(int page) { this.page = page; } public int getLimit() { return limit; } public void setLimit(int limit) { this.limit = limit; } } 3. mapper文件中查询列表可以这么写 <select id="queryList" parameterType="map" resultType="com.paulandcode.entity.Test"> SELECT id, name FROM test <choose> <when test="sidx.trim() != '' and sidx.trim() != ''"> ORDER BY ${sidx} ${order} </when> <otherwise> ORDER BY id DESC </otherwise> </choose> <if test="offset != null and limit != null"> LIMIT #{offset}, #{limit} </if> </select> 二十一. Shiro工具类 1. Maven导包 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.3.2</version> </dependency> 2. 工具类 import com.paulandcode.entity.SysUserEntity; import org.apache.shiro.SecurityUtils; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; /** * Shiro工具类 * * @author paulandcode * @since 2018年7月26日 下午4:29:19 */ public class ShiroUtils { /** * * 获得ShiroSession. * @return */ public static Session getSession() { return SecurityUtils.getSubject().getSession(); } /** * * 获得Subject. * @return */ public static Subject getSubject() { return SecurityUtils.getSubject(); } /** * * 获得Princpal, 此处的SysUserEntity是自定义UserRealm中的doGetAuthenticationInfo方法中设置的. * @return */ public static SysUserEntity getUserEntity() { return (SysUserEntity)SecurityUtils.getSubject().getPrincipal(); } /** * * 获得用户id. * @return */ public static Long getUserId() { return getUserEntity().getUserId(); } /** * * ShiroSession中放置某个键值对 * @param key * @param value */ public static void setSessionAttribute(Object key, Object value) { getSession().setAttribute(key, value); } /** * * 获得ShiroSession中某个键值对 * @param key * @return */ public static Object getSessionAttribute(Object key) { return getSession().getAttribute(key); } /** * * 是否已经登录. * @return */ public static boolean isLogin() { return SecurityUtils.getSubject().getPrincipal() != null; } /** * * 退出登录. */ public static void logout() { SecurityUtils.getSubject().logout(); } /** * * 获得验证码, 获得一次后, 从ShiroSession中移除, 无法再次获得. * @param key * @return */ public static String getKaptcha(String key) { String kaptcha = getSessionAttribute(key).toString(); getSession().removeAttribute(key); return kaptcha; } } 二十二. SpringContext工具类 import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * SpringContext 工具类 * * @author paulandcode * @since 2018年7月26日 下午4:29:19 */ @Component public class SpringContextUtils implements ApplicationContextAware { public static ApplicationContext applicationContext; /** * * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextUtils.applicationContext = applicationContext; } /** * * 获得Bean. * @param name Bean的名称 * @return */ public static Object getBean(String name) { return applicationContext.getBean(name); } /** * * 获得Bean. * @param name Bean的名称 * @param requiredType 类型 * @return */ public static <T> T getBean(String name, Class<T> requiredType) { return applicationContext.getBean(name, requiredType); } /** * * 是否包含某个Bean. * @param name Bean的名称 * @return */ public static boolean containsBean(String name) { return applicationContext.containsBean(name); } /** * * Bean是否是单例. * @param name Bean的名称 * @return */ public static boolean isSingleton(String name) { return applicationContext.isSingleton(name); } /** * * Bean的类型. * @param name Bean的名称 * @return */ public static Class<? extends Object> getType(String name) { return applicationContext.getType(name); } } 二十三. Properties载入工具类 1. 工具类如下 import java.io.IOException; import java.io.InputStreamReader; import java.util.Properties; /** * properties载入工具类 * * @author paulandcode * @email paulandcode@gmail.com * @date 2017年5月18日 下午13:27:13 */ public class PropertiesLoader { private final Properties properties; public PropertiesLoader(String... resourcePaths) { properties = loadProperties(resourcePaths); } /** * 载入多个properties文件 * * @param resourcePaths * @return */ private Properties loadProperties(String[] resourcePaths) { Properties props = new Properties(); for (String location : resourcePaths) { InputStreamReader is = null; try { is = new InputStreamReader(PropertiesLoader.class.getClassLoader().getResourceAsStream(location), "UTF-8"); props.load(is); } catch (Exception e) { } finally { try { is.close(); } catch (IOException e) { } } } return props; } /** * 获得字符串参数 * * @param key * @return */ public String getConfig(String key) { if (properties.containsKey(key)) { return properties.getProperty(key); } return ""; } /** * * 获得数字参数 * @param key * @return */ public int getIntConfig(String key) { return Integer.parseInt(getConfig(key)); } } 2. 使用 public static PropertiesLoader loader = new PropertiesLoader("config/config.properties"); public void test() { String content = loader.getConfig("content"); } 二十四. Java执行Bat命令(或其他命令) 下面代码中的"Bat Finished! "是为了标记Bat执行结束, 可以在Bat文件的最后加入"echo Bat Finished! "来标记Bat执行结束. "Bat Success! "是为了标记Bat执行成功, "Bat Fail! "标记Bat执行失败, 可以将Bat文件进行相应的echo输出达到这样的效果. 这样做的目的是为了让java知道Bat是否成功执行结束, 若程序无需知道是否执行结束, 则Process process = processBuilder.start();这一句代码之后的其他代码可以去掉. package com.ribeen.utils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; /** * 执行bat命令 * * @author paulandcode paulandcode@gmail.com * @date 2018/10/9 14:59 */ public class BatUtils { /** * 执行kettle命令 * * @param batPath bat文件路径, 如: E:/test/test.bat * @param args 参数, 最多可以有9个参数, 从左到右代表1到9, 在Bat文件中用1%到9%表示参数 * @return boolean 执行成功或失败 */ public static boolean doBat(String batPath, String... args) { boolean result = false; String[] command; if (args == null || args.length == 0) { command = new String[]{batPath}; } else { command = new String[args.length + 1]; command[0] = batPath; System.arraycopy(args, 0, command, 1, args.length); } ProcessBuilder processBuilder = new ProcessBuilder(command); processBuilder.redirectErrorStream(true); try { Process process = processBuilder.start(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)); String line; while ((line = bufferedReader.readLine()) != null) { System.out.println(line); // 如果命令执行结束 if (line.contains("Bat Finished! ")) { // 执行结束后再执行一行, 表示执行成功或者失败 line = bufferedReader.readLine(); System.out.println(line); if (line.contains("Bat Success! ")) { result = true; } else if (line.contains("Bat Fail! ")){ // 若执行失败, 则默认result为false } break; } } } catch (IOException e) { e.printStackTrace(); } return result; } } 二十五. 不使用Request获得Web项目的全路径 String path = Test.class.getResource("").getFile(); 假如Test.class类文件在blog项目的com/paulandcode/utils目录下, 则上面的path值为: /D:/Tomcat/webapps/blog/WEB-INF/classes/com/paulandcode/utils/ 注意: 得到的值前后都有个斜杠 二十六. 下划线与驼峰相互转换 package com.product.utils; import java.util.HashMap; import java.util.Map; /** * 下划线与驼峰相互转换 * * @author paulandcode paulandcode@gmail.com * @date 2018/10/4 14:21 */ public class HumpUtils { private static final char UNDERLINE = '_'; /** * 数组由下划线转换为驼峰 * * @param arr 带有下划线的数组 * @return java.util.Map<java.lang.String,V> */ public static String[] arrUnderlineToHump(String[] arr) { if (arr == null) { return null; } String[] newArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { newArr[i] = toHump(arr[i]); } return newArr; } /** * 数组由驼峰转换为下划线 * * @param arr 带有下划线的数组 * @return java.util.Map<java.lang.String,V> */ public static String[] arrHumpToUnderline(String[] arr) { if (arr == null) { return null; } String[] newArr = new String[arr.length]; for (int i = 0; i < arr.length; i++) { newArr[i] = toUnderline(arr[i]); } return newArr; } /** * 将Map中的key由下划线转换为驼峰 * * @param map 带有下划线的map * @return java.util.Map<java.lang.String,V> */ public static <V> Map<String, V> mapKeyUnderlineToHump(Map<String, V> map) { if (map == null) { return null; } Map<String, V> newMap = new HashMap<>(map.size()); for (Map.Entry<String, V> entry : map.entrySet()) { String key = entry.getKey(); String newKey = toHump(key); newMap.put(newKey, entry.getValue()); } return newMap; } /** * 将Map中的key由驼峰转换为下划线 * * @param map 带有驼峰的map * @return java.util.Map<java.lang.String,V> */ public static <V> Map<String, V> mapKeyHumpToUnderline(Map<String, V> map) { if (map == null) { return null; } Map<String, V> newMap = new HashMap<>(map.size()); for (Map.Entry<String, V> entry : map.entrySet()) { String key = entry.getKey(); String newKey = toUnderline(key); newMap.put(newKey, entry.getValue()); } return newMap; } /** * 下划线转驼峰 * * @param colName 字符串 * @return java.lang.String */ public static String toHump(String colName) { if (colName == null) { return null; } StringBuilder sb = new StringBuilder(); String[] str = colName.toLowerCase().split(String.valueOf(UNDERLINE)); for (String s : str) { if (s.length() == 1) { sb.append(s.toUpperCase()); continue; } if (s.length() > 1) { sb.append(s.substring(0, 1).toUpperCase()); sb.append(s.substring(1)); } } String result = sb.toString(); return result.substring(0, 1).toLowerCase() + result.substring(1); } /** * 驼峰转下划线 * * @param colName 字符串 * @return java.lang.String */ private static String toUnderline(String colName) { if (colName == null) { return null; } String result = colName.replaceAll("[A-Z]", String.valueOf(UNDERLINE) + "$0"); return result.toLowerCase(); } } 二十七. Web响应信息工具类 package com.paulandcode.common; import java.util.HashMap; import java.util.Map; /** * Web响应信息 * 前后端通信时一般0或200为正常, 1或500以及其他为异常 * 数据库中字段的值一般0为false, 1为true * * @author paulandcode paulandcode@gmail.com * @since 2019/3/27 17:23 */ public class R extends HashMap<String, Object> { private static final long serialVersionUID = -7035368021961298846L; /** * 构造函数, 默认成功. */ private R() { put("code", 0); } /** * 响应未知异常. * * @return com.paulandcode.common.R */ public static R err() { return err(1, "未知异常, 请联系管理员! "); } /** * 响应自定义异常信息. * * @param msg 异常信息 * @return com.paulandcode.common.R */ public static R err(String msg) { return err(1, msg); } /** * 响应自定义异常信息和状态码. * * @param code 状态码 * @param msg 异常信息 * @return com.paulandcode.common.R */ public static R err(int code, String msg) { R r = new R(); r.put("code", code); r.put("msg", msg); return r; } /** * 响应成功并自定义信息. * * @param msg 成功信息 * @return com.paulandcode.common.R */ public static R msg(String msg) { R r = new R(); r.put("msg", msg); return r; } /** * 响应成功. * * @return com.paulandcode.common.R */ public static R ok() { return new R(); } /** * 响应成功并自定义信息. * * @param data 成功数据 * @return com.paulandcode.common.R */ public static R ok(Object data) { return ok().data(data); } /** * 响应成功并加入一些键值对. * * @param map 键值对 * @return com.paulandcode.common.R */ public static R ok(Map<String, Object> map) { R r = new R(); r.putAll(map); return r; } /** * 响应信息移除指定键值对. * * @param key 键 * @return com.paulandcode.common.R */ public R remove(String key) { super.remove(key); return this; } /** * 响应中加入一个键值对. * * @param key 键 * @param value 值 * @return com.paulandcode.common.R */ @Override public R put(String key, Object value) { super.put(key, value); return this; } /** * 放入响应数据 * * @param data 响应数据 * @return com.paulandcode.common.R */ public R data(Object data) { return put("data", data); } /** * 放入数据总数 * * @param count 总数 * @return com.paulandcode.common.R */ public R count(int count) { return put("count", count); } }
一. 简化了哪些 @Data: 可以不用写set, set, 构造器, equals, toString, hashCode等方法, 在IDEA中按Ctrl + F12可以看到隐藏的这些方法 @Slf4j: 不用写如下代码: private final Logger log = LoggerFactory.getLogger(LoggerTest.class); 二. 在IDEA中需要装插件: Settings中的Plugins下搜索lombok 三. Maven导包 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> 四. 在application.yml文件中配置日志级别 # 公共配置 logging: level: # 指定日志等级 root: debug 五. 使用 @Slf4j public class Test { public String testLog(){ log.info("######### info #########"); log.debug("######### debug #########"); log.error("######### error #########"); return null; } }
一. 通过命令行使用Git(以Windows为例) 1.安装Git-2.12.2.2-64-bit.exe 2.任何目录下, 右键, Git Bash Here 3.初次安装git配置用户名和邮箱 git config --global user.name "paul" git config --global user.email "paulandcode@gmail.com" 4.查看是否已有ssh公钥 type %userprofile%\.ssh\id_rsa.pub 若没有, 则会提示找不到文件 5.若没有, 则去生成公钥 ssh-keygen -t rsa -C "paulandcode@gmail.com" -b 4096 生成过程中会让你设置公钥路径, 直接回车使用默认路径即可还会让你设置密码, 若不设置密码, 则直接回车即可 6.添加公钥到远程仓库 cat ~/.ssh/id_rsa.pub 上面的命令会获得公钥, 然后需要你手动将公钥添加到远程仓库(如GitHub) 7.若是搭建的gitlab私服,则连接仓库时会提示无法解析主机名, 此时要在C:/Windows/System32/drivers/etc下的hosts文件中加入一行代码 192.168.0.233 gitlab.ywz.com 8.若本地没有原始代码, 需要从远程Git仓库下载原始代码到本地 cd new_folder git clone ssh://git@github.com:paulandcode/blogs.git 9.若本地有原始代码, 远程Git仓库没有原始代码, 需要将原始代码上传到远程仓库. 若使用GitHub, 最好加上README.md, .gitignore, LICENSE这几个基本文件. cd existing_folder git init git remote add origin https://github.com/paulandcode/paulandcode_lucene.git git add . git commit -m "Initial commit" git push -u origin master 若提示: fatal: remote origin already exists, 则移除后再添加Git仓库 git remote rm origin 10.同步远程Git仓库代码到本地 git pull --rebase origin master 11.提交代码到本地Git仓库 git add test.html git commit -m "Commit test.html" 12.提交本地Git仓库代码到远程Git仓库 git push -u origin master 二. 通过Eclipse使用Git 1.Window --> Show View --> Other... 2.搜索git, 选择Git Repositories 3.先复制好Git的仓库路径(如: git@github.com:paulandcode/blogs.git), 然后在Eclipse弹出的窗口粘贴路径, 最后一直点击下一步, 并选择本地项目保存路径即可下载整个项目到本地. 4.更新代码选中要更新的文件夹点击右键 --> Team --> Pull (将服务器中新增的代码拉到本地, 若有冲突, 则会报错, 只会拉到在本地git仓库, 不会拉到本地代码中, 并且在项目名右侧会有↓提示, 例:offweb[offweb master ↓1], 这表示本地git仓库有1个文件等待拉取) 5.提交代码选中要提交的文件夹点击右键 --> Team --> Add to Index --> Commit And Push(将本地代码提交到git服务器, 若有冲突, 则会报错, 只会提交到在本地git仓库, 不会提交到git服务器, 并且在项目名右侧会有↑提示, 例:offweb[offweb master ↑1], 这表示本地git仓库有1个文件等待提交) 6.解决冲突不论是先Pull还是先Push, 都有一个规律:只有Pull之后才会出现冲突信息, 只有出现冲突信息后, 下一个push才可以提交成功. 所以解决冲突分三步: 第一步, Pull后出现冲突信息(Pull --> Push --> Pull 或者 Push --> Pull); 第二步, 解决冲突; 第三步, Push 7.使用Eclipse自带的Merge Tool解决冲突选中项目根文件夹点击右键 --> Team --> Synchronize Workspace(与资源库同步) --> 有冲突的代码处(红色双向箭头)右键Merge Tool解决冲突 --> 解决完后右键Add to Index --> Commit And Push 三. 通过IDEA使用Git(IDEA, PyCharm, AndroidStudio等这些套路都类似) 1.在IDEA上通过Git或者GitHub检出项目 2.更新和提交(1) 按键上图5个按键分别是:更新、提交、比较、历史、Revert (2) 文件类型白:无修改;蓝:修改; 红:新增未Add Git; 绿:新增Add to Git (3) 更新点击更新后,请在Event Log页面查看结果(可能有种种原因更新失败) (4) 提交1> 点击Commit 按钮, 会直接提交至本地库. 更新至远程库需要再Push一次: VCS --> Git --> Push 2>点击Commit and Push: 提交到本地, 并且提交到远程仓库, Commit and Push按钮的位置在提交页面Commit按钮旁边的下拉箭头 (5) 比较在History中右键compare 四. docker搭建GitLab的docker-compose.yml文件 version: "3.5" services: gitlab: image: gitlab/gitlab-ce:10.5.4-ce.0 restart: always container_name: gitlab ports: - "8085:80" - "2222:22" hostname: "gitlab.ywz.com" environment: GITLAB_OMNIBUS_CONFIG: | gitlab_rails['gitlab_shell_ssh_port'] = 2222 volumes: - type: volume source: config target: /etc/gitlab - type: volume source: logs target: /var/log/gitlab - type: volume source: data target: /var/opt/gitlab volumes: config: name: gitlab_config logs: name: gitlab_logs data: name: gitlab_data 五. .gitignore文件 .mymetadata .checkstyle .classpath .project .class .war .zip .rar .idea *.iml *.py[cod] .settings/* /indexes/* /src/main/webapp/WEB-INF/classes/* /src/main/webapp/userfiles/* */target/ */target/* 小知识: Windows如何新建以"."开头的文件(如.gitignore文件)情况: Windows下, 如果新建以"."开头的文件, 会提示: 必须键入文件名.解决: 在文件名后面再加个".", 例如".gitignore.", 则可以新建.gitignore文件
1.启动Eclipse时重新设置workspace Window—>Preferences—>General—>Startup and Shutdown—>Workspaces—>选中Prompt for workspace on startup 2.启动Eclipse时刷新workspace Window—>Preferences—>General—>Startup and Shutdown—>Workspaces—>选中Refresh workspace on startup 3.设置web项目启动后默认弹出浏览器 Window—>Preferences—>General—>Web Browser—>在External web browser中New 4.Eclipse修改jsp的默认编码 Window—>Preferences->Web->JSP Files->Encoding 5.关闭Eclipse的jap页面错误检查 Window—>Preferences->Validation-> 去掉对应的对勾 JSP Content Validator JSP文本验证 Manual 提示 JSP Syntax Validator JSP语法验证 Build 编译 6.Eclipse修改字体大小 Window—>Preferences—>General->Appearance->Colors and Font->Basic->Text Font 7.Eclipse修改工作空间的默认编码 Window—>Preferences—>General->Workspace->右侧Text file encoding 8.选中了一个单词 “String” ,其他相同的单词“String” 的颜色就会变化 "Window"-"preferences"-"Java"-"Editor"-"Mark Occurrences"复选框勾选 9.改变classes的位置,发布到 WEB-INF 下的 classes 里 a.eclipse新建的Dynamic web project 默认是将类编译在build如果在eclipse中配置了tomcate(server项),用自带的发布功能,是能自动识别的。 b.自已修改到WEB-INF下也是可以的,要修改eclipse设置,具体做法右键你的工程-〉java Build Path-〉source项页面最下面的default out folder,选择到你的web-inf 目录的classes下,没有要新建,好像您没有使用自动发布功能. 10.源码包导入方法 a、Navigate-->Open Type-->输入自己想要查看的类-->双击要查看类-->如果没有源码就会弹出源码选择框-->选择本地源码即可 b、右键需要导入源码的项目-->Bulid Path-->Configure Build path-->Libraries选项卡-->找到jar包-->展开-->选中Source attachment-->Edit-->选择本地源码 11.设置maven的配置文件 Window—>Preferences—>Maven->User Settings 设置完要点一下Update Settings