├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── README.md ├── log4j2.jpg ├── mvnw ├── mvnw.cmd ├── pom.xml └── src └── main ├── java └── com │ └── zhangjp │ └── log4j2 │ └── desensitization │ ├── AddCardOutputVo.java │ ├── CustCancellableTransactionInputVo.java │ ├── DesensitizationApplication.java │ ├── JacksonTestController.java │ ├── config │ └── ArgumentHadlerConfiguration.java │ ├── desensitization │ ├── DefaultDevice.java │ ├── DesensitizationStrategy.java │ ├── DesensitizationUtils.java │ └── MD5Device.java │ ├── encry │ ├── AESUtil.java │ ├── ArgumentResolver.java │ └── JacksonEncry.java │ ├── fastjson │ └── DesensitizationJsonFilter.java │ ├── fliter │ └── LogFilter.java │ └── plugin │ ├── JsonDesensitization.java │ ├── JsonRegexReplaces.java │ └── MyPatternLayout.java └── resources ├── application.yml └── log4j2.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | logs/ 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | /build/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | https://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | import java.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if (mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if (mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if (!outputFile.getParentFile().exists()) { 87 | if (!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangjunp/desensitization/3e0ea842af314bc6d842e3014dcb35707db058f1/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 日志脱敏 2 | 3 | ##### 写在前边:此demo主要介绍使用两种方式解决日志脱敏,当然也可以使用其他方式,比如通过脱敏工具类,或者自定义注解实现脱敏字段以及脱敏规则等等…… 4 | 5 | ###### 如有更好的实现方式或者思路,欢迎相互交流 ,邮箱: `zjp20123258@163.com` 6 | 7 | - 一、基于Log4j2实现日志脱敏,借助Log4j2的自定义插件特性,自定义JSON格式数据的脱敏插件,基于正则表达式实现,并支持自定义脱敏的规则;可在原有基础上扩展使其支持脱敏toString格式的数据。 8 | 9 | - 二、 基于fastJson的ValueFliter实现字段脱敏 10 | 11 | ###### 使用方式(在log4j2.xml)配置文件中: 12 | 13 | ```java 14 | 15 | 16 | 17 | 18 | 19 | 20 | ``` 21 | 1. keys: 为要脱敏的字段,以英文符号隔开,支持多个; 22 | 1. methodName: 为针对此keys的脱敏规则,支持自定义; 23 | 24 | **自定义方式如下:** 25 | ```java 26 | /** 27 | * 创建时间 2019年四月04日 星期四 10:45 28 | * 作者: zhangjunping 29 | * 描述:MD5方式脱敏器 30 | */ 31 | @Component 32 | public class MD5Device implements DesensitizationStrategy { 33 | @Override 34 | public String produceCipherText(String plaintext) { 35 | return DigestUtils.md5DigestAsHex(plaintext.getBytes()); 36 | } 37 | 38 | @PostConstruct 39 | @Override 40 | public void addDeviceToMap() { 41 | // 此处map的key即为,标签内methodName的属性 42 | DEVICE_METHOD_MAP.put("md5",this); 43 | } 44 | } 45 | 46 | ``` 47 | ###### 实现思路,借助Layout 最后一层,拦截日志,进行正则匹配替换脱敏字段 48 | 49 | 50 | ![log4j2类图](https://github.com/191824852/desensitization/blob/master/log4j2.jpg "log4j2类图") 51 | 52 | 53 | 54 | ###### 此demo中,还包含了,日志统一记录业务代码,以及请求源IP的例子! 有需要的可以看一下,实现起来比较简单,利于日志排查! 55 | 56 | 57 | ### End 58 | -------------------------------------------------------------------------------- /log4j2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangjunp/desensitization/3e0ea842af314bc6d842e3014dcb35707db058f1/log4j2.jpg -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | ########################################################################################## 204 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 205 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 206 | ########################################################################################## 207 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 208 | if [ "$MVNW_VERBOSE" = true ]; then 209 | echo "Found .mvn/wrapper/maven-wrapper.jar" 210 | fi 211 | else 212 | if [ "$MVNW_VERBOSE" = true ]; then 213 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 214 | fi 215 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 216 | while IFS="=" read key value; do 217 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 218 | esac 219 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 220 | if [ "$MVNW_VERBOSE" = true ]; then 221 | echo "Downloading from: $jarUrl" 222 | fi 223 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 224 | 225 | if command -v wget > /dev/null; then 226 | if [ "$MVNW_VERBOSE" = true ]; then 227 | echo "Found wget ... using wget" 228 | fi 229 | wget "$jarUrl" -O "$wrapperJarPath" 230 | elif command -v curl > /dev/null; then 231 | if [ "$MVNW_VERBOSE" = true ]; then 232 | echo "Found curl ... using curl" 233 | fi 234 | curl -o "$wrapperJarPath" "$jarUrl" 235 | else 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Falling back to using Java to download" 238 | fi 239 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 240 | if [ -e "$javaClass" ]; then 241 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 242 | if [ "$MVNW_VERBOSE" = true ]; then 243 | echo " - Compiling MavenWrapperDownloader.java ..." 244 | fi 245 | # Compiling the Java class 246 | ("$JAVA_HOME/bin/javac" "$javaClass") 247 | fi 248 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 249 | # Running the downloader 250 | if [ "$MVNW_VERBOSE" = true ]; then 251 | echo " - Running MavenWrapperDownloader.java ..." 252 | fi 253 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 254 | fi 255 | fi 256 | fi 257 | fi 258 | ########################################################################################## 259 | # End of extension 260 | ########################################################################################## 261 | 262 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 263 | if [ "$MVNW_VERBOSE" = true ]; then 264 | echo $MAVEN_PROJECTBASEDIR 265 | fi 266 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 267 | 268 | # For Cygwin, switch paths to Windows format before running java 269 | if $cygwin; then 270 | [ -n "$M2_HOME" ] && 271 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 272 | [ -n "$JAVA_HOME" ] && 273 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 274 | [ -n "$CLASSPATH" ] && 275 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 276 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 277 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 278 | fi 279 | 280 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 281 | 282 | exec "$JAVACMD" \ 283 | $MAVEN_OPTS \ 284 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 285 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 286 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 287 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 124 | FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( 125 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 126 | ) 127 | 128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 130 | if exist %WRAPPER_JAR% ( 131 | echo Found %WRAPPER_JAR% 132 | ) else ( 133 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 134 | echo Downloading from: %DOWNLOAD_URL% 135 | powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" 136 | echo Finished downloading %WRAPPER_JAR% 137 | ) 138 | @REM End of extension 139 | 140 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 141 | if ERRORLEVEL 1 goto error 142 | goto end 143 | 144 | :error 145 | set ERROR_CODE=1 146 | 147 | :end 148 | @endlocal & set ERROR_CODE=%ERROR_CODE% 149 | 150 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 151 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 152 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 153 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 154 | :skipRcPost 155 | 156 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 157 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 158 | 159 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 160 | 161 | exit /B %ERROR_CODE% 162 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 1.5.16.RELEASE 9 | 10 | 11 | com.sunjinke.log4j2 12 | desensitization 13 | 0.0.1-SNAPSHOT 14 | desensitization 15 | log4j2 for data desensitization 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-logging 34 | 35 | 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-log4j2 41 | 42 | 43 | org.apache.logging.log4j 44 | log4j-web 45 | 46 | 47 | com.alibaba 48 | fastjson 49 | 1.2.55 50 | true 51 | 52 | 53 | 54 | org.apache.commons 55 | commons-lang3 56 | 3.7 57 | 59 | 60 | org.projectlombok 61 | lombok 62 | 63 | 64 | commons-codec 65 | commons-codec 66 | 1.13 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.springframework.boot 74 | spring-boot-maven-plugin 75 | 76 | 77 | 78 | org.apache.maven.plugins 79 | maven-compiler-plugin 80 | 3.1 81 | 82 | 83 | log4j-plugin-processor 84 | 85 | compile 86 | 87 | process-classes 88 | 89 | only 90 | 91 | 92 | org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/AddCardOutputVo.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 5 | import com.zhangjp.log4j2.desensitization.encry.JacksonEncry; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * 金证增加银行卡出参VO 11 | * 接口编码:430104 12 | * 13 | * @author lvzhitao 14 | * 15 | */ 16 | public class AddCardOutputVo implements Serializable { 17 | 18 | private static final long serialVersionUID = -6930856532101893114L; 19 | @JsonProperty(value = "appsheetserialno") 20 | @JsonSerialize(using = JacksonEncry.class) 21 | private String appSheetSerialNo; 22 | 23 | @JsonProperty(value = "moneyaccount") 24 | private String moneyAccount; 25 | 26 | @JsonProperty(value = "transactionaccountid") 27 | private String transactionAccountId; 28 | 29 | public String getAppSheetSerialNo() { 30 | return appSheetSerialNo; 31 | } 32 | public void setAppSheetSerialNo(String appSheetSerialNo) { 33 | this.appSheetSerialNo = appSheetSerialNo; 34 | } 35 | public String getMoneyAccount() { 36 | return moneyAccount; 37 | } 38 | public void setMoneyAccount(String moneyAccount) { 39 | this.moneyAccount = moneyAccount; 40 | } 41 | public String getTransactionAccountId() { 42 | return transactionAccountId; 43 | } 44 | public void setTransactionAccountId(String transactionAccountId) { 45 | this.transactionAccountId = transactionAccountId; 46 | } 47 | @Override 48 | public String toString() { 49 | return "AddCardOutputVo [appSheetSerialNo=" + appSheetSerialNo + ", moneyAccount=" + moneyAccount 50 | + ", transactionAccountId=" + transactionAccountId + "]"; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/CustCancellableTransactionInputVo.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 金证查询可撤单交易申请列表入参VO 9 | * 接口编码:430311 10 | * 11 | * @author lvzhitao 12 | * 13 | */ 14 | public class CustCancellableTransactionInputVo implements Serializable { 15 | 16 | private static final long serialVersionUID = 1L; 17 | 18 | @JsonProperty(value = "custno") 19 | private String custno; 20 | @JsonProperty(value = "fundcode") 21 | private String fundCode; 22 | @JsonProperty(value = "ismoneyfund") 23 | private String isMoneyFund; 24 | @JsonProperty(value = "pagesize") 25 | private String pageSize; 26 | @JsonProperty(value = "source") 27 | private String source; 28 | @JsonProperty(value = "startindex") 29 | private String startIndex; 30 | @JsonProperty(value = "appsheetserialno") 31 | private String appSheetSerialNo; 32 | 33 | 34 | public String getCustno() { 35 | return custno; 36 | } 37 | public void setCustno(String custno) { 38 | this.custno = custno; 39 | } 40 | public String getFundCode() { 41 | return fundCode; 42 | } 43 | public void setFundCode(String fundCode) { 44 | this.fundCode = fundCode; 45 | } 46 | public String getIsMoneyFund() { 47 | return isMoneyFund; 48 | } 49 | public void setIsMoneyFund(String isMoneyFund) { 50 | this.isMoneyFund = isMoneyFund; 51 | } 52 | public String getPageSize() { 53 | return pageSize; 54 | } 55 | public void setPageSize(String pageSize) { 56 | this.pageSize = pageSize; 57 | } 58 | public String getSource() { 59 | return source; 60 | } 61 | public void setSource(String source) { 62 | this.source = source; 63 | } 64 | public String getStartIndex() { 65 | return startIndex; 66 | } 67 | public void setStartIndex(String startIndex) { 68 | this.startIndex = startIndex; 69 | } 70 | public String getAppSheetSerialNo() { 71 | return appSheetSerialNo; 72 | } 73 | public void setAppSheetSerialNo(String appSheetSerialNo) { 74 | this.appSheetSerialNo = appSheetSerialNo; 75 | } 76 | @Override 77 | public String toString() { 78 | return "CustCancellableTransactionInputVo [custno=" + custno + ", fundCode=" + fundCode + ", isMoneyFund=" 79 | + isMoneyFund + ", pageSize=" + pageSize + ", source=" + source + ", startIndex=" + startIndex 80 | + ", appSheetSerialNo=" + appSheetSerialNo + "]"; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/DesensitizationApplication.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.zhangjp.log4j2.desensitization.fastjson.DesensitizationJsonFilter; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.boot.web.servlet.ServletComponentScan; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import javax.annotation.Resource; 14 | 15 | @SpringBootApplication 16 | @RestController 17 | @ServletComponentScan 18 | public class DesensitizationApplication { 19 | private static final Logger logger = LoggerFactory.getLogger(DesensitizationApplication.class); 20 | 21 | @Resource 22 | private DesensitizationJsonFilter valueFilter; 23 | 24 | public static void main(String[] args) { 25 | SpringApplication.run(DesensitizationApplication.class, args); 26 | Test test = new Test("17699998888", "370281199911113090", "6217000088050017995", "dww123456zzz", "zhangjp@777.com"); 27 | logger.error("{}", JSON.toJSONString(test, true)); 28 | System.out.println("=====启动成功====="); 29 | logger.error("{}", JSON.toJSONString(new MyObj("fastJson", "zhangjp"), new DesensitizationJsonFilter())); 30 | 31 | } 32 | 33 | @GetMapping("/index") 34 | public String index() { 35 | Test test = new Test("17699998888", "370281199911113090", "6217000088050017995", "dww123456zzz", "zhangjp@777.com"); 36 | logger.error("{}", JSON.toJSONString(test, valueFilter)); 37 | logger.error("============end=============="); 38 | return "Index"; 39 | } 40 | 41 | 42 | static class MyObj { 43 | public MyObj(String fastJson, String name) { 44 | this.fastJson = fastJson; 45 | this.name = name; 46 | } 47 | 48 | private String fastJson; 49 | private String name; 50 | 51 | public String getName() { 52 | return name; 53 | } 54 | 55 | public void setName(String name) { 56 | this.name = name; 57 | } 58 | 59 | public String getFastJson() { 60 | return fastJson; 61 | } 62 | 63 | public void setFastJson(String fastJson) { 64 | this.fastJson = fastJson; 65 | } 66 | } 67 | 68 | static class Test { 69 | public Test(String cardtelno, String certificateno, String depositacct, String tpasswd, String email) { 70 | this.cardtelno = cardtelno; 71 | this.certificateno = certificateno; 72 | this.depositacct = depositacct; 73 | this.tpasswd = tpasswd; 74 | this.email = email; 75 | } 76 | 77 | private String cardtelno; 78 | private String certificateno; 79 | private String depositacct; 80 | private String tpasswd; 81 | private String email; 82 | 83 | 84 | public String getEmail() { 85 | return email; 86 | } 87 | 88 | public void setEmail(String email) { 89 | this.email = email; 90 | } 91 | 92 | public String getCardtelno() { 93 | return cardtelno; 94 | } 95 | 96 | public void setCardtelno(String cardtelno) { 97 | this.cardtelno = cardtelno; 98 | } 99 | 100 | public String getCertificateno() { 101 | return certificateno; 102 | } 103 | 104 | public void setCertificateno(String certificateno) { 105 | this.certificateno = certificateno; 106 | } 107 | 108 | public String getDepositacct() { 109 | return depositacct; 110 | } 111 | 112 | public void setDepositacct(String depositacct) { 113 | this.depositacct = depositacct; 114 | } 115 | 116 | public String getTpasswd() { 117 | return tpasswd; 118 | } 119 | 120 | public void setTpasswd(String tpasswd) { 121 | this.tpasswd = tpasswd; 122 | } 123 | 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/JacksonTestController.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization; 2 | 3 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | /** 8 | * 创建时间 2019年九月12日 星期四 15:38 9 | * 作者: zhangjp 10 | */ 11 | 12 | @RestController("jack") 13 | public class JacksonTestController { 14 | 15 | @GetMapping("/test") 16 | public AddCardOutputVo test(AddCardOutputVo addCardOutputVo){ 17 | addCardOutputVo.setAppSheetSerialNo("123456789"); 18 | return addCardOutputVo; 19 | } 20 | 21 | 22 | @GetMapping("/test1") 23 | public String test1(@JsonSerialize CustCancellableTransactionInputVo addCardOutputVo){ 24 | System.out.println("addCardOutputVo = " + addCardOutputVo.toString()); 25 | return addCardOutputVo.getAppSheetSerialNo(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/config/ArgumentHadlerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization.config; 2 | 3 | import com.zhangjp.log4j2.desensitization.encry.ArgumentResolver; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.method.support.HandlerMethodArgumentResolver; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 创建时间 2019年九月12日 星期四 17:14 12 | * 作者: zhangjp 13 | */ 14 | @Configuration 15 | public class ArgumentHadlerConfiguration extends WebMvcConfigurerAdapter { 16 | 17 | @Override 18 | public void addArgumentResolvers(List argumentResolvers) { 19 | super.addArgumentResolvers(argumentResolvers); 20 | argumentResolvers.add(new ArgumentResolver()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/desensitization/DefaultDevice.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization.desensitization; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import javax.annotation.PostConstruct; 6 | 7 | /** 8 | * 创建时间 2019年四月04日 星期四 10:45 9 | * 作者: zhangjp 10 | * 描述:默认脱敏器 11 | */ 12 | @Component 13 | public class DefaultDevice implements DesensitizationStrategy { 14 | 15 | @Override 16 | public String produceCipherText(String plaintext) { 17 | return "******"; 18 | } 19 | 20 | @PostConstruct 21 | @Override 22 | public void addDeviceToMap() { 23 | DEVICE_METHOD_MAP.put("default", this); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/desensitization/DesensitizationStrategy.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization.desensitization; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * 创建时间 2019年四月04日 星期四 10:43 8 | * 作者: zhangjp 9 | * 描述:脱敏器策略工厂 10 | */ 11 | public interface DesensitizationStrategy { 12 | // 类似于 策略工厂的 context 13 | Map DEVICE_METHOD_MAP = new HashMap<>(); 14 | 15 | /*** 16 | *

Description: 脱敏规则

17 | * @param plaintext 明文 18 | * @return java.lang.String 19 | * @author zhangjp 20 | * @date 2019/4/2 20:43 21 | */ 22 | String produceCipherText(String plaintext); 23 | 24 | void addDeviceToMap(); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/desensitization/DesensitizationUtils.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization.desensitization; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.springframework.util.DigestUtils; 5 | 6 | /** 7 | * 创建时间 2019年四月02日 星期二 17:00 8 | * 作者: zhangjp 9 | * 描述:脱敏工具类 10 | */ 11 | public class DesensitizationUtils extends StringUtils { 12 | 13 | /*** 14 | *

Description: md5 方式

15 | * @param plaintext 明文 16 | * @return java.lang.String 17 | * @author zhangjp 18 | * @date 2019/4/2 17:10 19 | */ 20 | public static String md5(String plaintext) { 21 | return DigestUtils.md5DigestAsHex(plaintext.getBytes()); 22 | } 23 | 24 | /*** 25 | *

Description: 手机号码前三后四脱敏

26 | * @param mobile 手机号 27 | * @return java.lang.String 28 | * @author zhangjp 29 | * @date 2019/4/2 17:11 30 | */ 31 | public static String mobileEncrypt(String mobile) { 32 | if (StringUtils.isEmpty(mobile) || (mobile.length() != 11)) { 33 | return mobile; 34 | } 35 | return mobile.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"); 36 | } 37 | 38 | /*** 39 | *

Description: 身份证前三后四脱敏

40 | * 41 | * @param id 身份证号 42 | * @return java.lang.String 43 | * @author zhangjp 44 | * @date 2019/4/2 17:12 45 | */ 46 | public static String idEncrypt(String id) { 47 | if (StringUtils.isEmpty(id) || (id.length() < 8)) { 48 | return id; 49 | } 50 | return id.replaceAll("(?<=\\w{4})\\w(?=\\w{4})", "*"); 51 | } 52 | 53 | /*** 54 | *

Description: 卡号三后四脱敏

55 | * @param card 卡号 56 | * @return java.lang.String 57 | * @author zhangjp 58 | * @date 2019/4/2 17:12 59 | */ 60 | public static String cardEncrypt(String card) { 61 | if (StringUtils.isEmpty(card) || (card.length() < 8)) { 62 | return card; 63 | } 64 | return card.replaceAll("(?<=\\w{4})\\w(?=\\w{4})", "*"); 65 | } 66 | 67 | /*** 68 | *

Description: 姓名截取第一个字脱敏

69 | * @param name 名字 70 | * @return java.lang.String 71 | * @author zhangjp 72 | * @date 2019/4/2 17:12 73 | */ 74 | public static String nameEncrypt(String name) { 75 | if (StringUtils.isEmpty(name) || (name.length() < 2)) { 76 | return name; 77 | } 78 | return "*" + name.substring(1); 79 | } 80 | 81 | /** 82 | * [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.com> 83 | * 84 | * @param email 邮箱 85 | * @return 脱敏后邮箱 86 | */ 87 | public static String emailEncrypt(String email) { 88 | if (StringUtils.isBlank(email)) { 89 | return ""; 90 | } 91 | int index = StringUtils.indexOf(email, "@"); 92 | if (index <= 3) 93 | return email; 94 | else 95 | return StringUtils.rightPad(StringUtils.left(email, 3), index, "*").concat(StringUtils.mid(email, index, StringUtils.length(email))); 96 | } 97 | 98 | /** 99 | * 判断subStr是否在str中 100 | * 12,13,a 是否包含数字1 false 101 | * 1,12,13,a 是否包含数字1 true 102 | * 103 | * @param str 字符串 104 | * @param subStr 需要判断的字符串 105 | * @param splitChar 分隔符 106 | */ 107 | public static boolean characterInString(String str, String subStr, char splitChar) { 108 | boolean result = false; 109 | int i = 0; 110 | while (i < str.length()) { 111 | // 分隔符直接跳过 112 | if (splitChar == str.charAt(i)) { 113 | i++; 114 | continue; 115 | } 116 | // 截取到下一分隔符直接的字符串 117 | int j = i + 1; 118 | StringBuilder sb = new StringBuilder().append(str.charAt(i)); 119 | while (j < str.length() && splitChar != str.charAt(j)) { 120 | sb.append(str.charAt(j)); 121 | j++; 122 | } 123 | 124 | // System.out.println(str); 125 | if (subStr.equals(sb.toString())) { 126 | result = true; 127 | break; 128 | } 129 | 130 | // 分隔符之后继续遍历 131 | i = j + 1; 132 | } 133 | return result; 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/desensitization/MD5Device.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization.desensitization; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.springframework.util.DigestUtils; 5 | 6 | import javax.annotation.PostConstruct; 7 | 8 | /** 9 | * 创建时间 2019年四月04日 星期四 10:45 10 | * 作者: zhangjp 11 | * 描述:MD5方式脱敏器 12 | */ 13 | @Component 14 | public class MD5Device implements DesensitizationStrategy { 15 | @Override 16 | public String produceCipherText(String plaintext) { 17 | return DigestUtils.md5DigestAsHex(plaintext.getBytes()); 18 | } 19 | 20 | @PostConstruct 21 | @Override 22 | public void addDeviceToMap() { 23 | DEVICE_METHOD_MAP.put("md5", this); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/encry/AESUtil.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization.encry; 2 | 3 | import org.apache.commons.codec.binary.Hex; 4 | import org.apache.commons.lang3.StringUtils; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import javax.crypto.Cipher; 9 | import javax.crypto.spec.SecretKeySpec; 10 | import java.io.UnsupportedEncodingException; 11 | 12 | /** 13 | * 创建时间 2019年七月18日 星期四 10:05 14 | * 描述:我家阳光818活动对接,Aes加密工具类 15 | */ 16 | public class AESUtil { 17 | private static final Logger LOG = LoggerFactory.getLogger(AESUtil.class); 18 | private static final String aesKey = "78dsfs54fs42afnlsale"; 19 | private static final String defaultCharset = "UTF-8"; 20 | 21 | 22 | 23 | /** 24 | * 使用aes加密 25 | * 功能和mysql的hex(AES_ENCRYPT(content,'key'))一样,使用utf-8编码 26 | * @param content 27 | * @param key 28 | * @return 29 | */ 30 | public static String AESEncrypt(String content, String key) { 31 | try { 32 | LOG.debug("加密前 <{}> ", content); 33 | if (StringUtils.isNotBlank(content)) { 34 | final Cipher encryptCipher = Cipher.getInstance("AES"); 35 | SecretKeySpec secretKeySpec = generateMySQLAESKey(key, defaultCharset); 36 | encryptCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); 37 | byte valBytes[] = encryptCipher.doFinal(content.getBytes(defaultCharset)); 38 | String r = new String(Hex.encodeHex(valBytes)); 39 | LOG.debug("加密后 <{}> ", r); 40 | return r; 41 | } 42 | } catch (Exception e) { 43 | LOG.error("AESEncrypt加密失败:{}",e); 44 | } 45 | return content; 46 | } 47 | 48 | /** 49 | * 使用aes解密, 50 | * 功能和mysql的AES_DECRYPT(unhex(content),'key')一样,使用utf-8编码 51 | * @param content 52 | * @param key 53 | * @return 54 | */ 55 | public static String AESDecrypt(String content, String key) { 56 | if (StringUtils.isNotBlank(content)) { 57 | if (StringUtils.isNumeric(content.substring(0, content.length() - 1))) { 58 | return content; 59 | } else { 60 | try { 61 | LOG.debug("解密前 <{}> ", content); 62 | Cipher decryptCipher = Cipher.getInstance("AES"); 63 | SecretKeySpec secretKeySpec = generateMySQLAESKey(key, "UTF-8"); 64 | decryptCipher.init(2, secretKeySpec); 65 | byte[] valBytes = decryptCipher.doFinal(Hex.decodeHex(content.toCharArray())); 66 | String r = new String(valBytes); 67 | LOG.debug("解密后 <{}> ", r); 68 | return r; 69 | } catch (Exception e) { 70 | LOG.debug("解密失败后 <{}> ", content); 71 | return content; 72 | } 73 | } 74 | } else { 75 | return content; 76 | } 77 | } 78 | 79 | /** 80 | * 使用aes加密,使用默认key 81 | * 功能和mysql的hex(AES_ENCRYPT(content,'key'))一样,使用utf-8编码 82 | * @param content 83 | * @return 84 | */ 85 | public static String AESEncrypt(String content) { 86 | return AESEncrypt(content, aesKey); 87 | } 88 | 89 | /** 90 | * 使用aes解密,使用默认key。 91 | * 功能和mysql的AES_DECRYPT(unhex(content),'key')一样,使用utf-8编码 92 | * @param content 93 | * @return 94 | * @throws Exception 95 | */ 96 | public static String AESDecrypt(String content) { 97 | return AESDecrypt(content, aesKey); 98 | } 99 | 100 | /** 101 | * @param key 102 | * @param encoding 103 | * @return 104 | */ 105 | public static SecretKeySpec generateMySQLAESKey(final String key, final String encoding) { 106 | try { 107 | final byte[] finalKey = new byte[16]; 108 | int i = 0; 109 | for (byte b : key.getBytes(encoding)) { 110 | finalKey[i++ % 16] ^= b; 111 | } 112 | return new SecretKeySpec(finalKey, "AES"); 113 | } catch (UnsupportedEncodingException e) { 114 | throw new RuntimeException(e); 115 | } 116 | } 117 | 118 | 119 | 120 | public static void main(String[] args) { 121 | String name = ""; 122 | String phone = "13513210010"; 123 | String certificate = ""; 124 | String aesname = AESEncrypt(name); 125 | String aesphone = AESEncrypt(phone); 126 | String aescertificate = AESEncrypt(certificate); 127 | System.out.println("-----------------AES解密------------------------"); 128 | AESDecrypt(name); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/encry/ArgumentResolver.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization.encry; 2 | 3 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 4 | import org.springframework.core.MethodParameter; 5 | import org.springframework.web.bind.support.WebDataBinderFactory; 6 | import org.springframework.web.context.request.NativeWebRequest; 7 | import org.springframework.web.method.support.HandlerMethodArgumentResolver; 8 | import org.springframework.web.method.support.ModelAndViewContainer; 9 | 10 | /** 11 | * 创建时间 2019年九月12日 星期四 17:10 12 | * 作者: zhangjp 13 | * 描述:TODO 14 | */ 15 | public class ArgumentResolver implements HandlerMethodArgumentResolver { 16 | 17 | public ArgumentResolver() {} 18 | 19 | @Override 20 | public boolean supportsParameter(MethodParameter parameter) { 21 | return parameter.hasParameterAnnotation(JsonSerialize.class); 22 | } 23 | 24 | @Override 25 | public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { 26 | System.out.println("parameter = " + parameter); 27 | return null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/encry/JacksonEncry.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization.encry; 2 | 3 | import com.fasterxml.jackson.core.JsonGenerator; 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.JsonSerializer; 6 | import com.fasterxml.jackson.databind.SerializerProvider; 7 | import org.apache.commons.lang3.StringUtils; 8 | 9 | import java.io.IOException; 10 | 11 | /** 12 | * 创建时间 2019年九月12日 星期四 15:44 13 | * 作者: zhangjp 14 | */ 15 | public class JacksonEncry extends JsonSerializer { 16 | @Override 17 | public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { 18 | System.out.println("value = " + value); 19 | if (!StringUtils.isEmpty (value)) { 20 | String s = AESUtil.AESEncrypt(value); 21 | jsonGenerator.writeString (s); 22 | }else { 23 | jsonGenerator.writeString (value); 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/fastjson/DesensitizationJsonFilter.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization.fastjson; 2 | 3 | import com.alibaba.fastjson.serializer.ValueFilter; 4 | import org.springframework.stereotype.Component; 5 | 6 | /** 7 | * 创建时间 2019年四月03日 星期三 9:07 8 | * 作者: zhangjp 9 | * 描述:TODO 基于FastJson的ValueFilter 实现 指定字段脱敏 10 | */ 11 | @Component 12 | public class DesensitizationJsonFilter implements ValueFilter { 13 | @Override 14 | public Object process(Object obj, String name, Object value) { 15 | if (name.toLowerCase().equals("fastjson")) { 16 | // 或者自定义规则 17 | return "******jsonFilter******"; 18 | } 19 | if (name.toLowerCase().equals("tpasswd")) { 20 | return "******jsonFilter******"; 21 | } 22 | return value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/fliter/LogFilter.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization.fliter; 2 | 3 | import lombok.extern.log4j.Log4j2; 4 | import org.apache.logging.log4j.ThreadContext; 5 | import org.springframework.beans.factory.annotation.Value; 6 | 7 | import javax.servlet.*; 8 | import javax.servlet.annotation.WebFilter; 9 | import java.io.IOException; 10 | import java.util.UUID; 11 | 12 | /** 13 | * 创建时间 2019年四月04日 星期四 11:18 14 | * 作者: zhangjp 15 | * 描述:这边是日志记录这次请求的追踪信息 以便查找信息 16 | */ 17 | @WebFilter 18 | @Log4j2 19 | public class LogFilter implements Filter { 20 | 21 | @Value("${log.remoteAddr}") 22 | private String remoteAddr; 23 | 24 | @Value("${log.reqId}") 25 | private String reqId; 26 | 27 | @Override 28 | public void init(FilterConfig filterConfig) throws ServletException { 29 | } 30 | 31 | @Override 32 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 33 | // TODO 这边看需求 可以从 header带来,很多微服务系统中,相互调用采用 加到请求头中将此值传递下去 34 | // 配合 其他 微服务路由追踪插件来实现 追踪 35 | String reqIdValue = UUID.randomUUID().toString(); 36 | String remoteAddrValue = request.getRemoteAddr(); 37 | ThreadContext.put(remoteAddr, remoteAddrValue); 38 | ThreadContext.put(reqId, reqIdValue); 39 | log.info("-------请求开始,此次业务代码:{},请求源IP:{}------", reqIdValue, remoteAddrValue); 40 | chain.doFilter(request, response); 41 | log.info("-------请求结束,此次业务代码:{},请求源IP:{}------", reqIdValue, remoteAddrValue); 42 | ThreadContext.clearMap(); 43 | 44 | 45 | } 46 | 47 | @Override 48 | public void destroy() { 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/plugin/JsonDesensitization.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization.plugin; 2 | 3 | import com.zhangjp.log4j2.desensitization.desensitization.DesensitizationStrategy; 4 | import org.apache.logging.log4j.Logger; 5 | import org.apache.logging.log4j.core.config.plugins.Plugin; 6 | import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 7 | import org.apache.logging.log4j.core.config.plugins.PluginFactory; 8 | import org.apache.logging.log4j.status.StatusLogger; 9 | 10 | import java.util.regex.Matcher; 11 | import java.util.regex.Pattern; 12 | 13 | 14 | /** 15 | * 创建时间 2019年四月01日 星期一 9:39 16 | * 作者: zhangjp 17 | * 描述:json日志格式脱敏 18 | */ 19 | @Plugin(name = "jsonReplace", category = "Core", printObject = true) 20 | public final class JsonDesensitization { 21 | private static final Logger LOGGER = StatusLogger.getLogger(); 22 | private String keys; 23 | private String methodName; 24 | 25 | private JsonDesensitization(final String keys, final String methodName) { 26 | this.keys = keys; 27 | this.methodName = methodName; 28 | } 29 | 30 | public String format(String msg) { 31 | String[] split = keys.split(","); 32 | StringBuilder sb = new StringBuilder("("); 33 | for (int i = 0; i < split.length; i++) { 34 | sb.append("\"").append(split[i]).append("\"").append("|"); 35 | if (i == split.length - 1) { 36 | sb.append("\"").append(split[i]).append("\""); 37 | } 38 | } 39 | sb.append(")(:\")([^\"]*)(\")"); 40 | Matcher matcher = Pattern.compile(sb.toString()).matcher(msg); 41 | if (matcher.find()) { 42 | String group = matcher.group(3); 43 | if (null != DesensitizationStrategy.DEVICE_METHOD_MAP.get(methodName)) { 44 | String cipherText = DesensitizationStrategy.DEVICE_METHOD_MAP.get(methodName).produceCipherText(group); 45 | msg = matcher.replaceAll("$1".concat("$2").concat(cipherText).concat("$4")); 46 | } else { 47 | LOGGER.warn("脱敏方法名:{},不存在,请检查脱敏方法名是否正确!", methodName); 48 | } 49 | } 50 | return msg; 51 | } 52 | 53 | @PluginFactory 54 | public static JsonDesensitization createRegexReplacement( 55 | @PluginAttribute("keys") final String keys, 56 | @PluginAttribute("methodName") final String methodName) { 57 | if (keys == null) { 58 | LOGGER.error("The json keys is required"); 59 | return null; 60 | } 61 | if (methodName == null) { 62 | LOGGER.error("A value string is required"); 63 | } 64 | return new JsonDesensitization(keys, methodName); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/plugin/JsonRegexReplaces.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization.plugin; 2 | 3 | import org.apache.logging.log4j.Logger; 4 | import org.apache.logging.log4j.core.config.plugins.Plugin; 5 | import org.apache.logging.log4j.core.config.plugins.PluginElement; 6 | import org.apache.logging.log4j.core.config.plugins.PluginFactory; 7 | import org.apache.logging.log4j.core.pattern.RegexReplacement; 8 | import org.apache.logging.log4j.status.StatusLogger; 9 | 10 | /** 11 | * 创建时间 2019年四月01日 星期一 9:07 12 | * 作者: zhangjp 13 | * 描述:自定义插件(基于正则表达式实现日志脱敏) 14 | */ 15 | @Plugin(name = "jsonReplaces", category = "Core", printObject = true) 16 | public class JsonRegexReplaces { 17 | private static final Logger LOGGER = StatusLogger.getLogger(); 18 | 19 | // replace标签,复用log4j已有plugin, replaces 下可以0,1,多个replace 20 | private final RegexReplacement[] replaces; 21 | 22 | // 自定义JSON格式 的replace 封装 json字符串的判断,以及脱敏规则 23 | private final JsonDesensitization[] jsonDesensitization; 24 | 25 | 26 | private JsonRegexReplaces(RegexReplacement[] replaces, JsonDesensitization[] jsonDesensitization) { 27 | this.replaces = replaces; 28 | this.jsonDesensitization = jsonDesensitization; 29 | } 30 | 31 | /** 32 | * 格式化输出日志信息, 此方法会执行多个正则表达式匹配与替换 33 | */ 34 | public String format(String msg) { 35 | for (JsonDesensitization json : jsonDesensitization) { 36 | msg = json.format(msg); 37 | } 38 | for (RegexReplacement replace : replaces) { 39 | msg = replace.format(msg); 40 | } 41 | return msg; 42 | } 43 | 44 | /** 45 | * 实现pluginFactory, 用于生成pugin 46 | */ 47 | @PluginFactory 48 | public static JsonRegexReplaces createRegexReplacement( 49 | @PluginElement("replace") final RegexReplacement[] replaces, 50 | @PluginElement("jsonReplace") final JsonDesensitization[] jsonReplace) { 51 | if (replaces == null) { 52 | LOGGER.warn("have the replace , but no replace is set"); 53 | return null; 54 | } 55 | if (jsonReplace.length == 0) { 56 | LOGGER.warn("have the jsonReplace , but no jsonReplace is set"); 57 | return null; 58 | } 59 | return new JsonRegexReplaces(replaces, jsonReplace); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/zhangjp/log4j2/desensitization/plugin/MyPatternLayout.java: -------------------------------------------------------------------------------- 1 | package com.zhangjp.log4j2.desensitization.plugin; 2 | 3 | import org.apache.logging.log4j.core.Layout; 4 | import org.apache.logging.log4j.core.LogEvent; 5 | import org.apache.logging.log4j.core.config.Configuration; 6 | import org.apache.logging.log4j.core.config.DefaultConfiguration; 7 | import org.apache.logging.log4j.core.config.Node; 8 | import org.apache.logging.log4j.core.config.plugins.*; 9 | import org.apache.logging.log4j.core.layout.*; 10 | import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; 11 | import org.apache.logging.log4j.core.pattern.PatternFormatter; 12 | import org.apache.logging.log4j.core.pattern.PatternParser; 13 | import org.apache.logging.log4j.util.Strings; 14 | 15 | import java.nio.charset.Charset; 16 | import java.util.Arrays; 17 | import java.util.List; 18 | 19 | /** 20 | * 创建时间 2019年三月28日 星期四 10:30 21 | * 作者: zhangjp 22 | * 描述:自定义脱敏的log4j2 Layout插件 23 | */ 24 | @Plugin(name = "MyPatternLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true) 25 | public final class MyPatternLayout extends AbstractStringLayout { 26 | 27 | /** 28 | * Default pattern string for log output. Currently set to the string "%m%n" which just prints the 29 | * application supplied message. 30 | */ 31 | public static final String DEFAULT_CONVERSION_PATTERN = "%m%n"; 32 | 33 | /** 34 | * Key to identify pattern converters. 35 | */ 36 | public static final String KEY = "Converter"; 37 | 38 | /** 39 | * Conversion pattern. 40 | */ 41 | private final String conversionPattern; 42 | private final PatternSelector patternSelector; 43 | private final Serializer eventSerializer; 44 | 45 | /** 46 | * Constructs a PatternLayout using the supplied conversion pattern. 47 | * 48 | * @param config The Configuration. 49 | * @param replace The regular expression to match. 50 | * @param eventPattern conversion pattern. 51 | * @param patternSelector The PatternSelector. 52 | * @param charset The character set. 53 | * @param alwaysWriteExceptions Whether or not exceptions should always be handled in this pattern (if {@code true}, 54 | * exceptions will be written even if the pattern does not specify so). 55 | * @param noConsoleNoAnsi If {@code "true"} (default) and {@link System#console()} is null, do not output ANSI escape codes 56 | * @param headerPattern header conversion pattern. 57 | * @param footerPattern footer conversion pattern. 58 | */ 59 | private MyPatternLayout(final Configuration config, final JsonRegexReplaces replace, final String eventPattern, 60 | final PatternSelector patternSelector, final Charset charset, final boolean alwaysWriteExceptions, 61 | final boolean noConsoleNoAnsi, final String headerPattern, final String footerPattern) { 62 | super(config, charset, 63 | createSerializer(config, replace, headerPattern, null, patternSelector, alwaysWriteExceptions, 64 | noConsoleNoAnsi), 65 | createSerializer(config, replace, footerPattern, null, patternSelector, alwaysWriteExceptions, 66 | noConsoleNoAnsi)); 67 | this.conversionPattern = eventPattern; 68 | this.patternSelector = patternSelector; 69 | this.eventSerializer = createSerializer(config, replace, eventPattern, DEFAULT_CONVERSION_PATTERN, 70 | patternSelector, alwaysWriteExceptions, noConsoleNoAnsi); 71 | } 72 | 73 | public static Serializer createSerializer(final Configuration configuration, final JsonRegexReplaces replace, 74 | final String pattern, final String defaultPattern, final PatternSelector patternSelector, 75 | final boolean alwaysWriteExceptions, final boolean noConsoleNoAnsi) { 76 | if (Strings.isEmpty(pattern) && Strings.isEmpty(defaultPattern)) { 77 | return null; 78 | } 79 | if (patternSelector == null) { 80 | try { 81 | final PatternParser parser = createPatternParser(configuration); 82 | final List list = parser.parse(pattern == null ? defaultPattern : pattern, 83 | alwaysWriteExceptions, noConsoleNoAnsi); 84 | final PatternFormatter[] formatters = list.toArray(new PatternFormatter[0]); 85 | return new MyPatternLayout.PatternSerializer(formatters, replace); 86 | } catch (final RuntimeException ex) { 87 | throw new IllegalArgumentException("Cannot parse pattern '" + pattern + "'", ex); 88 | } 89 | } 90 | return new MyPatternLayout.PatternSelectorSerializer(patternSelector, replace); 91 | } 92 | 93 | /** 94 | * Gets the conversion pattern. 95 | * 96 | * @return the conversion pattern. 97 | */ 98 | public String getConversionPattern() { 99 | return conversionPattern; 100 | } 101 | 102 | 103 | /** 104 | * Formats a logging event to a writer. 105 | * 106 | * @param event logging event to be formatted. 107 | * @return The event formatted as a String. 108 | */ 109 | @Override 110 | public String toSerializable(final LogEvent event) { 111 | return eventSerializer.toSerializable(event); 112 | } 113 | 114 | @Override 115 | public void encode(final LogEvent event, final ByteBufferDestination destination) { 116 | if (!(eventSerializer instanceof Serializer2)) { 117 | super.encode(event, destination); 118 | return; 119 | } 120 | final StringBuilder text = toText((Serializer2) eventSerializer, event, getStringBuilder()); 121 | final Encoder encoder = getStringBuilderEncoder(); 122 | encoder.encode(text, destination); 123 | trimToMaxSize(text); 124 | } 125 | 126 | /** 127 | * Creates a text representation of the specified log event 128 | * and writes it into the specified StringBuilder. 129 | *

130 | * Implementations are free to return a new StringBuilder if they can 131 | * detect in advance that the specified StringBuilder is too small. 132 | */ 133 | private StringBuilder toText(final Serializer2 serializer, final LogEvent event, 134 | final StringBuilder destination) { 135 | return serializer.toSerializable(event, destination); 136 | } 137 | 138 | /** 139 | * Creates a PatternParser. 140 | * 141 | * @param config The Configuration. 142 | * @return The PatternParser. 143 | */ 144 | public static PatternParser createPatternParser(final Configuration config) { 145 | if (config == null) { 146 | return new PatternParser(config, KEY, LogEventPatternConverter.class); 147 | } 148 | PatternParser parser = config.getComponent(KEY); 149 | if (parser == null) { 150 | parser = new PatternParser(config, KEY, LogEventPatternConverter.class); 151 | config.addComponent(KEY, parser); 152 | parser = config.getComponent(KEY); 153 | } 154 | return parser; 155 | } 156 | 157 | @Override 158 | public String toString() { 159 | return patternSelector == null ? conversionPattern : patternSelector.toString(); 160 | } 161 | 162 | /** 163 | * Creates a pattern layout. 164 | * 165 | * @param pattern The pattern. If not specified, defaults to DEFAULT_CONVERSION_PATTERN. 166 | * @param patternSelector Allows different patterns to be used based on some selection criteria. 167 | * @param config The Configuration. Some Converters require access to the Interpolator. 168 | * @param replace A Regex replacement String. 169 | * @param charset The character set. The platform default is used if not specified. 170 | * @param alwaysWriteExceptions If {@code "true"} (default) exceptions are always written even if the pattern contains no exception tokens. 171 | * @param noConsoleNoAnsi If {@code "true"} (default is false) and {@link System#console()} is null, do not output ANSI escape codes 172 | * @param headerPattern The footer to place at the top of the document, once. 173 | * @param footerPattern The footer to place at the bottom of the document, once. 174 | * @return The PatternLayout. 175 | */ 176 | @PluginFactory 177 | public static MyPatternLayout createLayout( 178 | @PluginAttribute(value = "pattern", defaultString = DEFAULT_CONVERSION_PATTERN) final String pattern, 179 | @PluginElement("PatternSelector") final PatternSelector patternSelector, 180 | @PluginConfiguration final Configuration config, 181 | @PluginElement("jsonReplaces") final JsonRegexReplaces replace, 182 | // LOG4J2-783 use platform default by default, so do not specify defaultString for charset 183 | @PluginAttribute(value = "charset") final Charset charset, 184 | @PluginAttribute(value = "alwaysWriteExceptions", defaultBoolean = true) final boolean alwaysWriteExceptions, 185 | @PluginAttribute(value = "noConsoleNoAnsi", defaultBoolean = false) final boolean noConsoleNoAnsi, 186 | @PluginAttribute("header") final String headerPattern, 187 | @PluginAttribute("footer") final String footerPattern) { 188 | return newBuilder() 189 | .withPattern(pattern) 190 | .withPatternSelector(patternSelector) 191 | .withConfiguration(config) 192 | .withRegexReplacement(replace) 193 | .withCharset(charset) 194 | .withAlwaysWriteExceptions(alwaysWriteExceptions) 195 | .withNoConsoleNoAnsi(noConsoleNoAnsi) 196 | .withHeader(headerPattern) 197 | .withFooter(footerPattern) 198 | .build(); 199 | } 200 | 201 | private static class PatternSerializer implements Serializer, Serializer2 { 202 | 203 | private final PatternFormatter[] formatters; 204 | private final JsonRegexReplaces replace; 205 | 206 | private PatternSerializer(final PatternFormatter[] formatters, final JsonRegexReplaces replace) { 207 | super(); 208 | this.formatters = formatters; 209 | this.replace = replace; 210 | } 211 | 212 | @Override 213 | public String toSerializable(final LogEvent event) { 214 | final StringBuilder sb = getStringBuilder(); 215 | try { 216 | return toSerializable(event, sb).toString(); 217 | } finally { 218 | trimToMaxSize(sb); 219 | } 220 | } 221 | 222 | @Override 223 | public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) { 224 | final int len = formatters.length; 225 | for (int i = 0; i < len; i++) { 226 | formatters[i].format(event, buffer); 227 | } 228 | if (replace != null) { // creates temporary objects 229 | String str = buffer.toString(); 230 | str = replace.format(str); 231 | buffer.setLength(0); 232 | buffer.append(str); 233 | } 234 | return buffer; 235 | } 236 | 237 | @Override 238 | public String toString() { 239 | final StringBuilder builder = new StringBuilder(); 240 | builder.append(super.toString()); 241 | builder.append("[formatters="); 242 | builder.append(Arrays.toString(formatters)); 243 | builder.append(", replace="); 244 | builder.append(replace); 245 | builder.append("]"); 246 | return builder.toString(); 247 | } 248 | } 249 | 250 | private static class PatternSelectorSerializer implements Serializer, Serializer2 { 251 | 252 | private final PatternSelector patternSelector; 253 | private final JsonRegexReplaces replace; 254 | 255 | private PatternSelectorSerializer(final PatternSelector patternSelector, final JsonRegexReplaces replace) { 256 | super(); 257 | this.patternSelector = patternSelector; 258 | this.replace = replace; 259 | } 260 | 261 | @Override 262 | public String toSerializable(final LogEvent event) { 263 | final StringBuilder sb = getStringBuilder(); 264 | try { 265 | return toSerializable(event, sb).toString(); 266 | } finally { 267 | trimToMaxSize(sb); 268 | } 269 | } 270 | 271 | @Override 272 | public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) { 273 | final PatternFormatter[] formatters = patternSelector.getFormatters(event); 274 | final int len = formatters.length; 275 | for (int i = 0; i < len; i++) { 276 | formatters[i].format(event, buffer); 277 | } 278 | if (replace != null) { // creates temporary objects 279 | String str = buffer.toString(); 280 | str = replace.format(str); 281 | buffer.setLength(0); 282 | buffer.append(str); 283 | } 284 | return buffer; 285 | } 286 | 287 | @Override 288 | public String toString() { 289 | return super.toString() + 290 | "[patternSelector=" + 291 | patternSelector + 292 | ", replaces=" + 293 | replace + 294 | "]"; 295 | } 296 | } 297 | 298 | /** 299 | * Creates a PatternLayout using the default options. These options include using UTF-8, the default conversion 300 | * pattern, exceptions being written, and with ANSI escape codes. 301 | * 302 | * @return the PatternLayout. 303 | * @see #DEFAULT_CONVERSION_PATTERN Default conversion pattern 304 | */ 305 | public static MyPatternLayout createDefaultLayout() { 306 | return newBuilder().build(); 307 | } 308 | 309 | /** 310 | * Creates a PatternLayout using the default options and the given configuration. These options include using UTF-8, 311 | * the default conversion pattern, exceptions being written, and with ANSI escape codes. 312 | * 313 | * @param configuration The Configuration. 314 | * @return the PatternLayout. 315 | * @see #DEFAULT_CONVERSION_PATTERN Default conversion pattern 316 | */ 317 | public static MyPatternLayout createDefaultLayout(final Configuration configuration) { 318 | return newBuilder().withConfiguration(configuration).build(); 319 | } 320 | 321 | /** 322 | * Creates a builder for a custom PatternLayout. 323 | * 324 | * @return a PatternLayout builder. 325 | */ 326 | @PluginBuilderFactory 327 | public static MyPatternLayout.Builder newBuilder() { 328 | return new MyPatternLayout.Builder(); 329 | } 330 | 331 | /** 332 | * Custom PatternLayout builder. Use the {@link PatternLayout#newBuilder() builder factory method} to create this. 333 | */ 334 | public static class Builder implements org.apache.logging.log4j.core.util.Builder { 335 | 336 | @PluginBuilderAttribute 337 | private String pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN; 338 | 339 | @PluginElement("PatternSelector") 340 | private PatternSelector patternSelector; 341 | 342 | @PluginConfiguration 343 | private Configuration configuration; 344 | 345 | @PluginElement("jsonReplaces") 346 | private JsonRegexReplaces regexReplacement; 347 | 348 | // LOG4J2-783 use platform default by default 349 | @PluginBuilderAttribute 350 | private Charset charset = Charset.defaultCharset(); 351 | 352 | @PluginBuilderAttribute 353 | private boolean alwaysWriteExceptions = true; 354 | 355 | @PluginBuilderAttribute 356 | private boolean noConsoleNoAnsi; 357 | 358 | @PluginBuilderAttribute 359 | private String header; 360 | 361 | @PluginBuilderAttribute 362 | private String footer; 363 | 364 | private Builder() { 365 | } 366 | 367 | // TODO: move javadocs from PluginFactory to here 368 | 369 | public MyPatternLayout.Builder withPattern(final String pattern) { 370 | this.pattern = pattern; 371 | return this; 372 | } 373 | 374 | public MyPatternLayout.Builder withPatternSelector(final PatternSelector patternSelector) { 375 | this.patternSelector = patternSelector; 376 | return this; 377 | } 378 | 379 | public MyPatternLayout.Builder withConfiguration(final Configuration configuration) { 380 | this.configuration = configuration; 381 | return this; 382 | } 383 | 384 | public MyPatternLayout.Builder withRegexReplacement(final JsonRegexReplaces regexReplacement) { 385 | this.regexReplacement = regexReplacement; 386 | return this; 387 | } 388 | 389 | public MyPatternLayout.Builder withCharset(final Charset charset) { 390 | // LOG4J2-783 if null, use platform default by default 391 | if (charset != null) { 392 | this.charset = charset; 393 | } 394 | return this; 395 | } 396 | 397 | public MyPatternLayout.Builder withAlwaysWriteExceptions(final boolean alwaysWriteExceptions) { 398 | this.alwaysWriteExceptions = alwaysWriteExceptions; 399 | return this; 400 | } 401 | 402 | public MyPatternLayout.Builder withNoConsoleNoAnsi(final boolean noConsoleNoAnsi) { 403 | this.noConsoleNoAnsi = noConsoleNoAnsi; 404 | return this; 405 | } 406 | 407 | public MyPatternLayout.Builder withHeader(final String header) { 408 | this.header = header; 409 | return this; 410 | } 411 | 412 | public MyPatternLayout.Builder withFooter(final String footer) { 413 | this.footer = footer; 414 | return this; 415 | } 416 | 417 | @Override 418 | public MyPatternLayout build() { 419 | if (configuration == null) { 420 | configuration = new DefaultConfiguration(); 421 | } 422 | return new MyPatternLayout(configuration, regexReplacement, pattern, patternSelector, charset, 423 | alwaysWriteExceptions, noConsoleNoAnsi, header, footer); 424 | } 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9000 3 | 4 | log: 5 | reqId: reqId 6 | remoteAddr: remoteAddr -------------------------------------------------------------------------------- /src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ./logs 8 | %highlight{【%X{reqId}】【%X{remoteAddr}】[%d{yyyy.MM.dd HH:mm:ss,sss z}] [%p] [%t] 9 | [%l] :%m%n} 10 | 11 | %highlight{===============测试版本 V.10 ===================} 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | --------------------------------------------------------------------------------