@@ -50,3 +50,6 @@ Temporary Items | |||||
.apdisk | .apdisk | ||||
/.sonar/ | /.sonar/ | ||||
sonar-project.properties | sonar-project.properties | ||||
!/.mvn/wrapper/maven-wrapper.jar | |||||
*.versionsBackup |
@@ -0,0 +1 @@ | |||||
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip |
@@ -8,15 +8,15 @@ language: java | |||||
jdk: | jdk: | ||||
- oraclejdk8 | - oraclejdk8 | ||||
script: "mvn clean package -Dmaven.test.skip=true" | |||||
script: "./mvnw clean package -DskipTests=true" | |||||
#script: | #script: | ||||
# - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar | # - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar | ||||
branches: | branches: | ||||
only: | only: | ||||
- develop | - develop | ||||
cache: | cache: | ||||
directories: | directories: | ||||
- '$HOME/.m2/repository' | - '$HOME/.m2/repository' | ||||
@@ -0,0 +1,2 @@ | |||||
#!/usr/bin/env bash | |||||
./mvnw org.codehaus.mojo:versions-maven-plugin:display-dependency-updates |
@@ -0,0 +1,2 @@ | |||||
#!/usr/bin/env bash | |||||
./mvnw org.codehaus.mojo:versions-maven-plugin:display-plugin-updates |
@@ -0,0 +1,2 @@ | |||||
#!/usr/bin/env bash | |||||
./mvnw org.codehaus.mojo:versions-maven-plugin:display-property-updates |
@@ -0,0 +1,236 @@ | |||||
#!/bin/sh | |||||
# ---------------------------------------------------------------------------- | |||||
# 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. | |||||
# ---------------------------------------------------------------------------- | |||||
# ---------------------------------------------------------------------------- | |||||
# Maven2 Start Up Batch script | |||||
# | |||||
# Required ENV vars: | |||||
# ------------------ | |||||
# JAVA_HOME - location of a JDK home dir | |||||
# | |||||
# Optional ENV vars | |||||
# ----------------- | |||||
# M2_HOME - location of maven2's installed home dir | |||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven | |||||
# e.g. to debug Maven itself, use | |||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 | |||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files | |||||
# ---------------------------------------------------------------------------- | |||||
if [ -z "$MAVEN_SKIP_RC" ] ; then | |||||
if [ -f /etc/mavenrc ] ; then | |||||
. /etc/mavenrc | |||||
fi | |||||
if [ -f "$HOME/.mavenrc" ] ; then | |||||
. "$HOME/.mavenrc" | |||||
fi | |||||
fi | |||||
# OS specific support. $var _must_ be set to either true or false. | |||||
cygwin=false; | |||||
darwin=false; | |||||
mingw=false | |||||
case "`uname`" in | |||||
CYGWIN*) cygwin=true ;; | |||||
MINGW*) mingw=true;; | |||||
Darwin*) darwin=true | |||||
# | |||||
# Look for the Apple JDKs first to preserve the existing behaviour, and then look | |||||
# for the new JDKs provided by Oracle. | |||||
# | |||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then | |||||
# | |||||
# Apple JDKs | |||||
# | |||||
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home | |||||
fi | |||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then | |||||
# | |||||
# Apple JDKs | |||||
# | |||||
export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home | |||||
fi | |||||
if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then | |||||
# | |||||
# Oracle JDKs | |||||
# | |||||
export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home | |||||
fi | |||||
if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then | |||||
# | |||||
# Apple JDKs | |||||
# | |||||
export JAVA_HOME=`/usr/libexec/java_home` | |||||
fi | |||||
;; | |||||
esac | |||||
if [ -z "$JAVA_HOME" ] ; then | |||||
if [ -r /etc/gentoo-release ] ; then | |||||
JAVA_HOME=`java-config --jre-home` | |||||
fi | |||||
fi | |||||
if [ -z "$M2_HOME" ] ; then | |||||
## resolve links - $0 may be a link to maven's home | |||||
PRG="$0" | |||||
# need this for relative symlinks | |||||
while [ -h "$PRG" ] ; do | |||||
ls=`ls -ld "$PRG"` | |||||
link=`expr "$ls" : '.*-> \(.*\)$'` | |||||
if expr "$link" : '/.*' > /dev/null; then | |||||
PRG="$link" | |||||
else | |||||
PRG="`dirname "$PRG"`/$link" | |||||
fi | |||||
done | |||||
saveddir=`pwd` | |||||
M2_HOME=`dirname "$PRG"`/.. | |||||
# make it fully qualified | |||||
M2_HOME=`cd "$M2_HOME" && pwd` | |||||
cd "$saveddir" | |||||
# echo Using m2 at $M2_HOME | |||||
fi | |||||
# For Cygwin, ensure paths are in UNIX format before anything is touched | |||||
if $cygwin ; then | |||||
[ -n "$M2_HOME" ] && | |||||
M2_HOME=`cygpath --unix "$M2_HOME"` | |||||
[ -n "$JAVA_HOME" ] && | |||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"` | |||||
[ -n "$CLASSPATH" ] && | |||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"` | |||||
fi | |||||
# For Migwn, ensure paths are in UNIX format before anything is touched | |||||
if $mingw ; then | |||||
[ -n "$M2_HOME" ] && | |||||
M2_HOME="`(cd "$M2_HOME"; pwd)`" | |||||
[ -n "$JAVA_HOME" ] && | |||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" | |||||
# TODO classpath? | |||||
fi | |||||
if [ -z "$JAVA_HOME" ]; then | |||||
javaExecutable="`which javac`" | |||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then | |||||
# readlink(1) is not available as standard on Solaris 10. | |||||
readLink=`which readlink` | |||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then | |||||
if $darwin ; then | |||||
javaHome="`dirname \"$javaExecutable\"`" | |||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" | |||||
else | |||||
javaExecutable="`readlink -f \"$javaExecutable\"`" | |||||
fi | |||||
javaHome="`dirname \"$javaExecutable\"`" | |||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'` | |||||
JAVA_HOME="$javaHome" | |||||
export JAVA_HOME | |||||
fi | |||||
fi | |||||
fi | |||||
if [ -z "$JAVACMD" ] ; then | |||||
if [ -n "$JAVA_HOME" ] ; then | |||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | |||||
# IBM's JDK on AIX uses strange locations for the executables | |||||
JAVACMD="$JAVA_HOME/jre/sh/java" | |||||
else | |||||
JAVACMD="$JAVA_HOME/bin/java" | |||||
fi | |||||
else | |||||
JAVACMD="`which java`" | |||||
fi | |||||
fi | |||||
if [ ! -x "$JAVACMD" ] ; then | |||||
echo "Error: JAVA_HOME is not defined correctly." >&2 | |||||
echo " We cannot execute $JAVACMD" >&2 | |||||
exit 1 | |||||
fi | |||||
if [ -z "$JAVA_HOME" ] ; then | |||||
echo "Warning: JAVA_HOME environment variable is not set." | |||||
fi | |||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher | |||||
# traverses directory structure from process work directory to filesystem root | |||||
# first directory with .mvn subdirectory is considered project base directory | |||||
find_maven_basedir() { | |||||
local basedir=$(pwd) | |||||
local wdir=$(pwd) | |||||
while [ "$wdir" != '/' ] ; do | |||||
if [ -d "$wdir"/.mvn ] ; then | |||||
basedir=$wdir | |||||
break | |||||
fi | |||||
wdir=$(cd "$wdir/.."; pwd) | |||||
done | |||||
echo "${basedir}" | |||||
} | |||||
# concatenates all lines of a file | |||||
concat_lines() { | |||||
if [ -f "$1" ]; then | |||||
echo "$(tr -s '\n' ' ' < "$1")" | |||||
fi | |||||
} | |||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} | |||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" | |||||
# For Cygwin, switch paths to Windows format before running java | |||||
if $cygwin; then | |||||
[ -n "$M2_HOME" ] && | |||||
M2_HOME=`cygpath --path --windows "$M2_HOME"` | |||||
[ -n "$JAVA_HOME" ] && | |||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` | |||||
[ -n "$CLASSPATH" ] && | |||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"` | |||||
[ -n "$MAVEN_PROJECTBASEDIR" ] && | |||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` | |||||
fi | |||||
# Provide a "standardized" way to retrieve the CLI args that will | |||||
# work with both Windows and non-Windows executions. | |||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" | |||||
export MAVEN_CMD_LINE_ARGS | |||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain | |||||
# avoid using MAVEN_CMD_LINE_ARGS below since that would loose parameter escaping in $@ | |||||
exec "$JAVACMD" \ | |||||
$MAVEN_OPTS \ | |||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ | |||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ | |||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" |
@@ -0,0 +1,146 @@ | |||||
@REM ---------------------------------------------------------------------------- | |||||
@REM Licensed to the Apache Software Foundation (ASF) under one | |||||
@REM or more contributor license agreements. See the NOTICE file | |||||
@REM distributed with this work for additional information | |||||
@REM regarding copyright ownership. The ASF licenses this file | |||||
@REM to you under the Apache License, Version 2.0 (the | |||||
@REM "License"); you may not use this file except in compliance | |||||
@REM with the License. You may obtain a copy of the License at | |||||
@REM | |||||
@REM http://www.apache.org/licenses/LICENSE-2.0 | |||||
@REM | |||||
@REM Unless required by applicable law or agreed to in writing, | |||||
@REM software distributed under the License is distributed on an | |||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |||||
@REM KIND, either express or implied. See the License for the | |||||
@REM specific language governing permissions and limitations | |||||
@REM under the License. | |||||
@REM ---------------------------------------------------------------------------- | |||||
@REM ---------------------------------------------------------------------------- | |||||
@REM Maven2 Start Up Batch script | |||||
@REM | |||||
@REM Required ENV vars: | |||||
@REM JAVA_HOME - location of a JDK home dir | |||||
@REM | |||||
@REM Optional ENV vars | |||||
@REM M2_HOME - location of maven2's installed home dir | |||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands | |||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending | |||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven | |||||
@REM e.g. to debug Maven itself, use | |||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 | |||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files | |||||
@REM ---------------------------------------------------------------------------- | |||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' | |||||
@echo off | |||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' | |||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% | |||||
@REM set %HOME% to equivalent of $HOME | |||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") | |||||
@REM Execute a user defined script before this one | |||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre | |||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending | |||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" | |||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" | |||||
:skipRcPre | |||||
@setlocal | |||||
set ERROR_CODE=0 | |||||
@REM To isolate internal variables from possible post scripts, we use another setlocal | |||||
@setlocal | |||||
@REM ==== START VALIDATION ==== | |||||
if not "%JAVA_HOME%" == "" goto OkJHome | |||||
echo. | |||||
echo Error: JAVA_HOME not found in your environment. >&2 | |||||
echo Please set the JAVA_HOME variable in your environment to match the >&2 | |||||
echo location of your Java installation. >&2 | |||||
echo. | |||||
goto error | |||||
:OkJHome | |||||
if exist "%JAVA_HOME%\bin\java.exe" goto init | |||||
echo. | |||||
echo Error: JAVA_HOME is set to an invalid directory. >&2 | |||||
echo JAVA_HOME = "%JAVA_HOME%" >&2 | |||||
echo Please set the JAVA_HOME variable in your environment to match the >&2 | |||||
echo location of your Java installation. >&2 | |||||
echo. | |||||
goto error | |||||
@REM ==== END VALIDATION ==== | |||||
:init | |||||
set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %* | |||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". | |||||
@REM Fallback to current working directory if not found. | |||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% | |||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir | |||||
set EXEC_DIR=%CD% | |||||
set WDIR=%EXEC_DIR% | |||||
:findBaseDir | |||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound | |||||
cd .. | |||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound | |||||
set WDIR=%CD% | |||||
goto findBaseDir | |||||
:baseDirFound | |||||
set MAVEN_PROJECTBASEDIR=%WDIR% | |||||
cd "%EXEC_DIR%" | |||||
goto endDetectBaseDir | |||||
:baseDirNotFound | |||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR% | |||||
cd "%EXEC_DIR%" | |||||
:endDetectBaseDir | |||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig | |||||
@setlocal EnableExtensions EnableDelayedExpansion | |||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a | |||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% | |||||
:endReadAdditionalConfig | |||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" | |||||
set WRAPPER_JAR=""%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"" | |||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain | |||||
# avoid using MAVEN_CMD_LINE_ARGS below since that would loose parameter escaping in %* | |||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* | |||||
if ERRORLEVEL 1 goto error | |||||
goto end | |||||
:error | |||||
set ERROR_CODE=1 | |||||
:end | |||||
@endlocal & set ERROR_CODE=%ERROR_CODE% | |||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost | |||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending | |||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" | |||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" | |||||
:skipRcPost | |||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' | |||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause | |||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% | |||||
exit /B %ERROR_CODE% |
@@ -6,9 +6,9 @@ | |||||
<modelVersion>4.0.0</modelVersion> | <modelVersion>4.0.0</modelVersion> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>weixin-java-parent</artifactId> | <artifactId>weixin-java-parent</artifactId> | ||||
<version>2.9.0</version> | |||||
<version>2.9.9.BETA</version> | |||||
<packaging>pom</packaging> | <packaging>pom</packaging> | ||||
<name>WeiXin Java Tools - Parent</name> | |||||
<name>Weixin Java Tools - Parent</name> | |||||
<description>微信公众号、企业号上级POM</description> | <description>微信公众号、企业号上级POM</description> | ||||
<url>https://github.com/wechat-group/weixin-java-tools</url> | <url>https://github.com/wechat-group/weixin-java-tools</url> | ||||
@@ -108,8 +108,6 @@ | |||||
<maven.compiler.target>1.7</maven.compiler.target> | <maven.compiler.target>1.7</maven.compiler.target> | ||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||
<downloadJavadocs>true</downloadJavadocs> | |||||
<downloadSources>true</downloadSources> | |||||
<httpclient.version>4.5</httpclient.version> | <httpclient.version>4.5</httpclient.version> | ||||
<jetty.version>9.3.0.RC0</jetty.version> | <jetty.version>9.3.0.RC0</jetty.version> | ||||
</properties> | </properties> | ||||
@@ -225,6 +223,13 @@ | |||||
<version>${jetty.version}</version> | <version>${jetty.version}</version> | ||||
<scope>test</scope> | <scope>test</scope> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>org.assertj</groupId> | |||||
<artifactId>assertj-guava</artifactId> | |||||
<version>3.0.0</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>redis.clients</groupId> | <groupId>redis.clients</groupId> | ||||
<artifactId>jedis</artifactId> | <artifactId>jedis</artifactId> | ||||
@@ -235,7 +240,7 @@ | |||||
<groupId>org.projectlombok</groupId> | <groupId>org.projectlombok</groupId> | ||||
<artifactId>lombok</artifactId> | <artifactId>lombok</artifactId> | ||||
<version>1.16.18</version> | <version>1.16.18</version> | ||||
<scope>compile</scope> | |||||
<scope>provided</scope> | |||||
</dependency> | </dependency> | ||||
</dependencies> | </dependencies> | ||||
</dependencyManagement> | </dependencyManagement> | ||||
@@ -353,15 +358,6 @@ | |||||
<goals>deploy</goals> | <goals>deploy</goals> | ||||
</configuration> | </configuration> | ||||
</plugin> | </plugin> | ||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-compiler-plugin</artifactId> | |||||
<version>3.6.0</version> | |||||
<configuration> | |||||
<encoding>UTF-8</encoding> | |||||
</configuration> | |||||
</plugin> | |||||
<plugin> | <plugin> | ||||
<groupId>org.apache.maven.plugins</groupId> | <groupId>org.apache.maven.plugins</groupId> | ||||
<artifactId>maven-checkstyle-plugin</artifactId> | <artifactId>maven-checkstyle-plugin</artifactId> | ||||
@@ -32,7 +32,7 @@ | |||||
<module name="IllegalTokenText"> | <module name="IllegalTokenText"> | ||||
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/> | <property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/> | ||||
<property name="format" value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/> | <property name="format" value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/> | ||||
<property name="message" value="Consider using special escape sequence instead of octal value or Unicode escaped value."/> | |||||
<property name="message" value="考虑使用特殊的转义字符,而非八进制值或者Unicode转义值。"/> | |||||
</module> | </module> | ||||
<module name="AvoidEscapedUnicodeCharacters"> | <module name="AvoidEscapedUnicodeCharacters"> | ||||
<property name="allowEscapesForControlCharacters" value="true"/> | <property name="allowEscapesForControlCharacters" value="true"/> | ||||
@@ -69,9 +69,9 @@ | |||||
<property name="allowEmptyTypes" value="true"/> | <property name="allowEmptyTypes" value="true"/> | ||||
<property name="allowEmptyLoops" value="true"/> | <property name="allowEmptyLoops" value="true"/> | ||||
<message key="ws.notFollowed" | <message key="ws.notFollowed" | ||||
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/> | |||||
value="WhitespaceAround: ''{0}''后面没有空格。Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/> | |||||
<message key="ws.notPreceded" | <message key="ws.notPreceded" | ||||
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/> | |||||
value="WhitespaceAround: ''{0}''前面没有加空格。"/> | |||||
</module> | </module> | ||||
<module name="OneStatementPerLine"/> | <module name="OneStatementPerLine"/> | ||||
<module name="MultipleVariableDeclarations"/> | <module name="MultipleVariableDeclarations"/> | ||||
@@ -100,11 +100,11 @@ | |||||
<module name="PackageName"> | <module name="PackageName"> | ||||
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/> | <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/> | ||||
<message key="name.invalidPattern" | <message key="name.invalidPattern" | ||||
value="Package name ''{0}'' must match pattern ''{1}''."/> | |||||
value="包名 ''{0}'' 必须匹配模式:''{1}''。"/> | |||||
</module> | </module> | ||||
<module name="TypeName"> | <module name="TypeName"> | ||||
<message key="name.invalidPattern" | <message key="name.invalidPattern" | ||||
value="Type name ''{0}'' must match pattern ''{1}''."/> | |||||
value="类型名 ''{0}'' 必须匹配模式:''{1}''。"/> | |||||
</module> | </module> | ||||
<module name="MemberName"> | <module name="MemberName"> | ||||
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/> | <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/> | ||||
@@ -114,28 +114,28 @@ | |||||
<module name="ParameterName"> | <module name="ParameterName"> | ||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/> | <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/> | ||||
<message key="name.invalidPattern" | <message key="name.invalidPattern" | ||||
value="Parameter name ''{0}'' must match pattern ''{1}''."/> | |||||
value="参数名''{0}'' 必须匹配模式:''{1}''。"/> | |||||
</module> | </module> | ||||
<module name="LocalVariableName"> | <module name="LocalVariableName"> | ||||
<property name="tokens" value="VARIABLE_DEF"/> | <property name="tokens" value="VARIABLE_DEF"/> | ||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/> | <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/> | ||||
<message key="name.invalidPattern" | <message key="name.invalidPattern" | ||||
value="Local variable name ''{0}'' must match pattern ''{1}''."/> | |||||
value="本地变量名 ''{0}'' 必须匹配模式:''{1}''。"/> | |||||
</module> | </module> | ||||
<module name="ClassTypeParameterName"> | <module name="ClassTypeParameterName"> | ||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/> | <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/> | ||||
<message key="name.invalidPattern" | <message key="name.invalidPattern" | ||||
value="Class type name ''{0}'' must match pattern ''{1}''."/> | |||||
value="类的类型名 ''{0}'' 必须匹配模式:''{1}''。"/> | |||||
</module> | </module> | ||||
<module name="MethodTypeParameterName"> | <module name="MethodTypeParameterName"> | ||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/> | <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/> | ||||
<message key="name.invalidPattern" | <message key="name.invalidPattern" | ||||
value="Method type name ''{0}'' must match pattern ''{1}''."/> | |||||
value="方法类型名 ''{0}'' 必须匹配模式:''{1}''。"/> | |||||
</module> | </module> | ||||
<module name="InterfaceTypeParameterName"> | <module name="InterfaceTypeParameterName"> | ||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/> | <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/> | ||||
<message key="name.invalidPattern" | <message key="name.invalidPattern" | ||||
value="Interface type name ''{0}'' must match pattern ''{1}''."/> | |||||
value="Interface type name ''{0}'' 必须匹配模式:''{1}''。"/> | |||||
</module> | </module> | ||||
<module name="NoFinalizer"/> | <module name="NoFinalizer"/> | ||||
<module name="GenericWhitespace"> | <module name="GenericWhitespace"> | ||||
@@ -148,14 +148,6 @@ | |||||
<message key="ws.notPreceded" | <message key="ws.notPreceded" | ||||
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/> | value="GenericWhitespace ''{0}'' is not preceded with whitespace."/> | ||||
</module> | </module> | ||||
<module name="Indentation"> | |||||
<property name="basicOffset" value="2"/> | |||||
<property name="braceAdjustment" value="0"/> | |||||
<property name="caseIndent" value="2"/> | |||||
<property name="throwsIndent" value="4"/> | |||||
<property name="lineWrappingIndentation" value="4"/> | |||||
<property name="arrayInitIndent" value="2"/> | |||||
</module> | |||||
<module name="AbbreviationAsWordInName"> | <module name="AbbreviationAsWordInName"> | ||||
<property name="ignoreFinal" value="false"/> | <property name="ignoreFinal" value="false"/> | ||||
<property name="allowedAbbreviationLength" value="1"/> | <property name="allowedAbbreviationLength" value="1"/> | ||||
@@ -186,7 +178,6 @@ | |||||
<property name="allowSamelineMultipleAnnotations" value="true"/> | <property name="allowSamelineMultipleAnnotations" value="true"/> | ||||
</module> | </module> | ||||
<module name="NonEmptyAtclauseDescription"/> | <module name="NonEmptyAtclauseDescription"/> | ||||
<module name="JavadocTagContinuationIndentation"/> | |||||
<module name="SummaryJavadoc"> | <module name="SummaryJavadoc"> | ||||
<property name="forbiddenSummaryFragments" value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/> | <property name="forbiddenSummaryFragments" value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/> | ||||
</module> | </module> | ||||
@@ -207,7 +198,7 @@ | |||||
<module name="MethodName"> | <module name="MethodName"> | ||||
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/> | <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/> | ||||
<message key="name.invalidPattern" | <message key="name.invalidPattern" | ||||
value="Method name ''{0}'' must match pattern ''{1}''."/> | |||||
value="方法名 ''{0}'' 必须匹配模式:''{1}''."/> | |||||
</module> | </module> | ||||
<module name="SingleLineJavadoc"> | <module name="SingleLineJavadoc"> | ||||
<property name="ignoreInlineTags" value="false"/> | <property name="ignoreInlineTags" value="false"/> | ||||
@@ -215,6 +206,5 @@ | |||||
<module name="EmptyCatchBlock"> | <module name="EmptyCatchBlock"> | ||||
<property name="exceptionVariableName" value="expected"/> | <property name="exceptionVariableName" value="expected"/> | ||||
</module> | </module> | ||||
<module name="CommentsIndentation"/> | |||||
</module> | </module> | ||||
</module> | </module> |
@@ -7,11 +7,11 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>weixin-java-parent</artifactId> | <artifactId>weixin-java-parent</artifactId> | ||||
<version>2.9.0</version> | |||||
<version>2.9.9.BETA</version> | |||||
</parent> | </parent> | ||||
<artifactId>weixin-java-common</artifactId> | <artifactId>weixin-java-common</artifactId> | ||||
<name>WeiXin Java Tools - Common</name> | |||||
<name>Weixin Java Tools - Common</name> | |||||
<description>微信公众号、企业号Java SDK Common</description> | <description>微信公众号、企业号Java SDK Common</description> | ||||
<dependencies> | <dependencies> | ||||
@@ -5,9 +5,9 @@ | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | * 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 not use this file except in compliance with | ||||
* the License. You may obtain a copy of the License at | * the License. You may obtain a copy of the License at | ||||
* | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | * http://www.apache.org/licenses/LICENSE-2.0 | ||||
* | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | ||||
* distributed under the License is distributed on an "AS IS" BASIS, | * distributed under the License is distributed on an "AS IS" BASIS, | ||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
@@ -23,9 +23,6 @@ package me.chanjar.weixin.common.session; | |||||
* | * | ||||
* @author Craig R. McClanahan | * @author Craig R. McClanahan | ||||
*/ | */ | ||||
public class Constants { | public class Constants { | ||||
public static final String Package = "me.chanjar.weixin.common.session"; | |||||
public static final String PACKAGE = "me.chanjar.weixin.common.session"; | |||||
} | } |
@@ -11,13 +11,12 @@ public class StandardSession implements WxSession, InternalSession { | |||||
/** | /** | ||||
* The string manager for this package. | * The string manager for this package. | ||||
*/ | */ | ||||
protected static final StringManager sm = StringManager.getManager(Constants.Package); | |||||
protected static final StringManager SM = StringManager.getManager(Constants.PACKAGE); | |||||
/** | /** | ||||
* Type array. | * Type array. | ||||
*/ | */ | ||||
private static final String[] EMPTY_ARRAY = new String[0]; | private static final String[] EMPTY_ARRAY = new String[0]; | ||||
// ------------------------------ WxSession | |||||
protected Map<String, Object> attributes = new ConcurrentHashMap<>(); | protected Map<String, Object> attributes = new ConcurrentHashMap<>(); | ||||
/** | /** | ||||
* The session identifier of this Session. | * The session identifier of this Session. | ||||
@@ -73,7 +72,7 @@ public class StandardSession implements WxSession, InternalSession { | |||||
if (!isValidInternal()) { | if (!isValidInternal()) { | ||||
throw new IllegalStateException | throw new IllegalStateException | ||||
(sm.getString("sessionImpl.getAttribute.ise")); | |||||
(SM.getString("sessionImpl.getAttribute.ise")); | |||||
} | } | ||||
if (name == null) { | if (name == null) { | ||||
@@ -86,7 +85,7 @@ public class StandardSession implements WxSession, InternalSession { | |||||
@Override | @Override | ||||
public Enumeration<String> getAttributeNames() { | public Enumeration<String> getAttributeNames() { | ||||
if (!isValidInternal()) { | if (!isValidInternal()) { | ||||
throw new IllegalStateException(sm.getString("sessionImpl.getAttributeNames.ise")); | |||||
throw new IllegalStateException(SM.getString("sessionImpl.getAttributeNames.ise")); | |||||
} | } | ||||
Set<String> names = new HashSet<>(); | Set<String> names = new HashSet<>(); | ||||
@@ -98,7 +97,7 @@ public class StandardSession implements WxSession, InternalSession { | |||||
public void setAttribute(String name, Object value) { | public void setAttribute(String name, Object value) { | ||||
// Name cannot be null | // Name cannot be null | ||||
if (name == null) { | if (name == null) { | ||||
throw new IllegalArgumentException(sm.getString("sessionImpl.setAttribute.namenull")); | |||||
throw new IllegalArgumentException(SM.getString("sessionImpl.setAttribute.namenull")); | |||||
} | } | ||||
// Null value is the same as removeAttribute() | // Null value is the same as removeAttribute() | ||||
@@ -109,7 +108,7 @@ public class StandardSession implements WxSession, InternalSession { | |||||
// Validate our current state | // Validate our current state | ||||
if (!isValidInternal()) { | if (!isValidInternal()) { | ||||
throw new IllegalStateException(sm.getString("sessionImpl.setAttribute.ise", getIdInternal())); | |||||
throw new IllegalStateException(SM.getString("sessionImpl.setAttribute.ise", getIdInternal())); | |||||
} | } | ||||
this.attributes.put(name, value); | this.attributes.put(name, value); | ||||
@@ -123,8 +122,9 @@ public class StandardSession implements WxSession, InternalSession { | |||||
@Override | @Override | ||||
public void invalidate() { | public void invalidate() { | ||||
if (!isValidInternal()) | |||||
throw new IllegalStateException(sm.getString("sessionImpl.invalidate.ise")); | |||||
if (!isValidInternal()) { | |||||
throw new IllegalStateException(SM.getString("sessionImpl.invalidate.ise")); | |||||
} | |||||
// Cause this session to expire | // Cause this session to expire | ||||
expire(); | expire(); | ||||
@@ -13,8 +13,7 @@ import java.util.concurrent.atomic.AtomicBoolean; | |||||
*/ | */ | ||||
public class StandardSessionManager implements WxSessionManager, InternalSessionManager { | public class StandardSessionManager implements WxSessionManager, InternalSessionManager { | ||||
protected static final StringManager sm = | |||||
StringManager.getManager(Constants.Package); | |||||
protected static final StringManager SM = StringManager.getManager(Constants.PACKAGE); | |||||
/** | /** | ||||
* The descriptive name of this Manager implementation (for logging). | * The descriptive name of this Manager implementation (for logging). | ||||
*/ | */ | ||||
@@ -82,7 +81,7 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||||
public WxSession getSession(String sessionId, boolean create) { | public WxSession getSession(String sessionId, boolean create) { | ||||
if (sessionId == null) { | if (sessionId == null) { | ||||
throw new IllegalStateException | throw new IllegalStateException | ||||
(sm.getString("sessionManagerImpl.getSession.ise")); | |||||
(SM.getString("sessionManagerImpl.getSession.ise")); | |||||
} | } | ||||
InternalSession session = findSession(sessionId); | InternalSession session = findSession(sessionId); | ||||
@@ -124,25 +123,24 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||||
@Override | @Override | ||||
public InternalSession findSession(String id) { | public InternalSession findSession(String id) { | ||||
if (id == null) | |||||
if (id == null) { | |||||
return (null); | return (null); | ||||
} | |||||
return this.sessions.get(id); | return this.sessions.get(id); | ||||
} | } | ||||
@Override | @Override | ||||
public InternalSession createSession(String sessionId) { | public InternalSession createSession(String sessionId) { | ||||
if (sessionId == null) { | if (sessionId == null) { | ||||
throw new IllegalStateException | throw new IllegalStateException | ||||
(sm.getString("sessionManagerImpl.createSession.ise")); | |||||
(SM.getString("sessionManagerImpl.createSession.ise")); | |||||
} | } | ||||
if ((this.maxActiveSessions >= 0) && | if ((this.maxActiveSessions >= 0) && | ||||
(getActiveSessions() >= this.maxActiveSessions)) { | (getActiveSessions() >= this.maxActiveSessions)) { | ||||
this.rejectedSessions++; | this.rejectedSessions++; | ||||
throw new TooManyActiveSessionsException( | throw new TooManyActiveSessionsException( | ||||
sm.getString("sessionManagerImpl.createSession.tmase"), | |||||
SM.getString("sessionManagerImpl.createSession.tmase"), | |||||
this.maxActiveSessions); | this.maxActiveSessions); | ||||
} | } | ||||
@@ -192,7 +190,7 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||||
while (true) { | while (true) { | ||||
try { | try { | ||||
// 每秒清理一次 | // 每秒清理一次 | ||||
Thread.sleep(StandardSessionManager.this.backgroundProcessorDelay * 1000l); | |||||
Thread.sleep(StandardSessionManager.this.backgroundProcessorDelay * 1000L); | |||||
backgroundProcess(); | backgroundProcess(); | ||||
} catch (InterruptedException e) { | } catch (InterruptedException e) { | ||||
StandardSessionManager.this.log.error("SessionManagerImpl.backgroundProcess error", e); | StandardSessionManager.this.log.error("SessionManagerImpl.backgroundProcess error", e); | ||||
@@ -230,8 +228,9 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||||
@Override | @Override | ||||
public void backgroundProcess() { | public void backgroundProcess() { | ||||
this.count = (this.count + 1) % this.processExpiresFrequency; | this.count = (this.count + 1) % this.processExpiresFrequency; | ||||
if (this.count == 0) | |||||
if (this.count == 0) { | |||||
processExpires(); | processExpires(); | ||||
} | |||||
} | } | ||||
/** | /** | ||||
@@ -243,16 +242,18 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||||
InternalSession sessions[] = findSessions(); | InternalSession sessions[] = findSessions(); | ||||
int expireHere = 0; | int expireHere = 0; | ||||
if (this.log.isDebugEnabled()) | |||||
if (this.log.isDebugEnabled()) { | |||||
this.log.debug("Start expire sessions {} at {} sessioncount {}", getName(), timeNow, sessions.length); | this.log.debug("Start expire sessions {} at {} sessioncount {}", getName(), timeNow, sessions.length); | ||||
for (int i = 0; i < sessions.length; i++) { | |||||
if (sessions[i] != null && !sessions[i].isValid()) { | |||||
} | |||||
for (InternalSession session : sessions) { | |||||
if (session != null && !session.isValid()) { | |||||
expireHere++; | expireHere++; | ||||
} | } | ||||
} | } | ||||
long timeEnd = System.currentTimeMillis(); | long timeEnd = System.currentTimeMillis(); | ||||
if (this.log.isDebugEnabled()) | |||||
if (this.log.isDebugEnabled()) { | |||||
this.log.debug("End expire sessions {} processingTime {} expired sessions: {}", getName(), timeEnd - timeNow, expireHere); | this.log.debug("End expire sessions {} processingTime {} expired sessions: {}", getName(), timeEnd - timeNow, expireHere); | ||||
} | |||||
this.processingTime += (timeEnd - timeNow); | this.processingTime += (timeEnd - timeNow); | ||||
} | } | ||||
@@ -32,7 +32,6 @@ public class BeanUtils { | |||||
* 检查bean里标记为@Required的field是否为空,为空则抛异常 | * 检查bean里标记为@Required的field是否为空,为空则抛异常 | ||||
* | * | ||||
* @param bean 要检查的bean对象 | * @param bean 要检查的bean对象 | ||||
* @throws WxErrorException | |||||
*/ | */ | ||||
public static void checkRequiredFields(Object bean) throws WxErrorException { | public static void checkRequiredFields(Object bean) throws WxErrorException { | ||||
List<String> requiredFields = Lists.newArrayList(); | List<String> requiredFields = Lists.newArrayList(); | ||||
@@ -68,39 +67,4 @@ public class BeanUtils { | |||||
} | } | ||||
} | } | ||||
/** | |||||
* 将bean按照@XStreamAlias标识的字符串内容生成以之为key的map对象 | |||||
* | |||||
* @param bean 包含@XStreamAlias的xml bean对象 | |||||
* @return map对象 | |||||
*/ | |||||
public static Map<String, String> xmlBean2Map(Object bean) { | |||||
Map<String, String> result = Maps.newHashMap(); | |||||
List<Field> fields = new ArrayList<>(Arrays.asList(bean.getClass().getDeclaredFields())); | |||||
fields.addAll(Arrays.asList(bean.getClass().getSuperclass().getDeclaredFields())); | |||||
for (Field field : fields) { | |||||
try { | |||||
boolean isAccessible = field.isAccessible(); | |||||
field.setAccessible(true); | |||||
if (field.get(bean) == null) { | |||||
field.setAccessible(isAccessible); | |||||
continue; | |||||
} | |||||
if (field.isAnnotationPresent(XStreamAlias.class)) { | |||||
result.put(field.getAnnotation(XStreamAlias.class).value(), field.get(bean).toString()); | |||||
} else if (!Modifier.isStatic(field.getModifiers())) { | |||||
//忽略掉静态成员变量 | |||||
result.put(field.getName(), field.get(bean).toString()); | |||||
} | |||||
field.setAccessible(isAccessible); | |||||
} catch (SecurityException | IllegalArgumentException | IllegalAccessException e) { | |||||
log.error(e.getMessage(), e); | |||||
} | |||||
} | |||||
return result; | |||||
} | |||||
} | } |
@@ -28,10 +28,10 @@ import java.util.Random; | |||||
*/ | */ | ||||
public class WxCryptUtil { | public class WxCryptUtil { | ||||
private static final Base64 base64 = new Base64(); | |||||
private static final Base64 BASE64 = new Base64(); | |||||
private static final Charset CHARSET = StandardCharsets.UTF_8; | private static final Charset CHARSET = StandardCharsets.UTF_8; | ||||
private static final ThreadLocal<DocumentBuilder> builderLocal = new ThreadLocal<DocumentBuilder>() { | |||||
private static final ThreadLocal<DocumentBuilder> BUILDER_LOCAL = new ThreadLocal<DocumentBuilder>() { | |||||
@Override | @Override | ||||
protected DocumentBuilder initialValue() { | protected DocumentBuilder initialValue() { | ||||
try { | try { | ||||
@@ -65,7 +65,7 @@ public class WxCryptUtil { | |||||
static String extractEncryptPart(String xml) { | static String extractEncryptPart(String xml) { | ||||
try { | try { | ||||
DocumentBuilder db = builderLocal.get(); | |||||
DocumentBuilder db = BUILDER_LOCAL.get(); | |||||
Document document = db.parse(new InputSource(new StringReader(xml))); | Document document = db.parse(new InputSource(new StringReader(xml))); | ||||
Element root = document.getDocumentElement(); | Element root = document.getDocumentElement(); | ||||
@@ -192,7 +192,7 @@ public class WxCryptUtil { | |||||
byte[] encrypted = cipher.doFinal(unencrypted); | byte[] encrypted = cipher.doFinal(unencrypted); | ||||
// 使用BASE64对加密后的字符串进行编码 | // 使用BASE64对加密后的字符串进行编码 | ||||
return base64.encodeToString(encrypted); | |||||
return BASE64.encodeToString(encrypted); | |||||
} catch (Exception e) { | } catch (Exception e) { | ||||
throw new RuntimeException(e); | throw new RuntimeException(e); | ||||
} | } | ||||
@@ -8,7 +8,7 @@ import java.nio.file.Files; | |||||
public class FileUtils { | public class FileUtils { | ||||
/** | /** | ||||
* 创建临时文件 | |||||
* 创建临时文件. | |||||
* | * | ||||
* @param inputStream 输入文件流 | * @param inputStream 输入文件流 | ||||
* @param name 文件名 | * @param name 文件名 | ||||
@@ -24,7 +24,7 @@ public class FileUtils { | |||||
} | } | ||||
/** | /** | ||||
* 创建临时文件 | |||||
* 创建临时文件. | |||||
* | * | ||||
* @param inputStream 输入文件流 | * @param inputStream 输入文件流 | ||||
* @param name 文件名 | * @param name 文件名 | ||||
@@ -4,5 +4,16 @@ package me.chanjar.weixin.common.util.http; | |||||
* Created by ecoolper on 2017/4/28. | * Created by ecoolper on 2017/4/28. | ||||
*/ | */ | ||||
public enum HttpType { | public enum HttpType { | ||||
JODD_HTTP, APACHE_HTTP, OK_HTTP; | |||||
/** | |||||
* jodd-http. | |||||
*/ | |||||
JODD_HTTP, | |||||
/** | |||||
* apache httpclient. | |||||
*/ | |||||
APACHE_HTTP, | |||||
/** | |||||
* okhttp. | |||||
*/ | |||||
OK_HTTP | |||||
} | } |
@@ -56,11 +56,14 @@ public class OkHttpMediaDownloadRequestExecutor extends BaseMediaDownloadRequest | |||||
return null; | return null; | ||||
} | } | ||||
File file = File.createTempFile(FilenameUtils.getBaseName(fileName), FilenameUtils.getExtension(fileName), | |||||
super.tmpDirFile); | |||||
File file = File.createTempFile( | |||||
FilenameUtils.getBaseName(fileName), "." + FilenameUtils.getExtension(fileName), super.tmpDirFile | |||||
); | |||||
try (BufferedSink sink = Okio.buffer(Okio.sink(file))) { | try (BufferedSink sink = Okio.buffer(Okio.sink(file))) { | ||||
sink.writeAll(response.body().source()); | sink.writeAll(response.body().source()); | ||||
} | } | ||||
file.deleteOnExit(); | file.deleteOnExit(); | ||||
return file; | return file; | ||||
} | } | ||||
@@ -1,14 +1,5 @@ | |||||
/* | |||||
* KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. | |||||
* | |||||
* This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended | |||||
* only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction | |||||
* arose from modification of the original source, or other redistribution of this source | |||||
* is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. | |||||
*/ | |||||
package me.chanjar.weixin.common.util.json; | package me.chanjar.weixin.common.util.json; | ||||
import com.google.common.collect.Lists; | import com.google.common.collect.Lists; | ||||
import com.google.gson.JsonArray; | import com.google.gson.JsonArray; | ||||
import com.google.gson.JsonElement; | import com.google.gson.JsonElement; | ||||
@@ -16,7 +7,6 @@ import com.google.gson.JsonObject; | |||||
import java.util.List; | import java.util.List; | ||||
public class GsonHelper { | public class GsonHelper { | ||||
public static boolean isNull(JsonElement element) { | public static boolean isNull(JsonElement element) { | ||||
@@ -77,7 +67,7 @@ public class GsonHelper { | |||||
public static long getAsPrimitiveLong(JsonElement element) { | public static long getAsPrimitiveLong(JsonElement element) { | ||||
Long r = getAsLong(element); | Long r = getAsLong(element); | ||||
return r == null ? 0l : r; | |||||
return r == null ? 0L : r; | |||||
} | } | ||||
public static Integer getAsInteger(JsonElement element) { | public static Integer getAsInteger(JsonElement element) { | ||||
@@ -95,7 +85,7 @@ public class GsonHelper { | |||||
public static boolean getAsPrimitiveBool(JsonElement element) { | public static boolean getAsPrimitiveBool(JsonElement element) { | ||||
Boolean r = getAsBoolean(element); | Boolean r = getAsBoolean(element); | ||||
return r != null && r.booleanValue(); | |||||
return r != null && r; | |||||
} | } | ||||
public static Double getAsDouble(JsonElement element) { | public static Double getAsDouble(JsonElement element) { | ||||
@@ -130,6 +120,20 @@ public class GsonHelper { | |||||
return result.toArray(new Integer[0]); | return result.toArray(new Integer[0]); | ||||
} | } | ||||
public static String[] getStringArray(JsonObject o, String string) { | |||||
JsonArray jsonArray = getAsJsonArray(o.getAsJsonArray(string)); | |||||
if (jsonArray == null) { | |||||
return null; | |||||
} | |||||
List<String> result = Lists.newArrayList(); | |||||
for (int i = 0; i < jsonArray.size(); i++) { | |||||
result.add(jsonArray.get(i).getAsString()); | |||||
} | |||||
return result.toArray(new String[0]); | |||||
} | |||||
public static Long[] getLongArray(JsonObject o, String string) { | public static Long[] getLongArray(JsonObject o, String string) { | ||||
JsonArray jsonArray = getAsJsonArray(o.getAsJsonArray(string)); | JsonArray jsonArray = getAsJsonArray(o.getAsJsonArray(string)); | ||||
if (jsonArray == null) { | if (jsonArray == null) { | ||||
@@ -1,11 +1,3 @@ | |||||
/* | |||||
* KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. | |||||
* | |||||
* This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended | |||||
* only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction | |||||
* arose from modification of the original source, or other redistribution of this source | |||||
* is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. | |||||
*/ | |||||
package me.chanjar.weixin.common.util.json; | package me.chanjar.weixin.common.util.json; | ||||
import com.google.gson.*; | import com.google.gson.*; | ||||
@@ -1,11 +1,3 @@ | |||||
/* | |||||
* KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. | |||||
* | |||||
* This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended | |||||
* only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction | |||||
* arose from modification of the original source, or other redistribution of this source | |||||
* is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. | |||||
*/ | |||||
package me.chanjar.weixin.common.util.json; | package me.chanjar.weixin.common.util.json; | ||||
import com.google.gson.*; | import com.google.gson.*; | ||||
@@ -1,11 +1,3 @@ | |||||
/* | |||||
* KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. | |||||
* | |||||
* This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended | |||||
* only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction | |||||
* arose from modification of the original source, or other redistribution of this source | |||||
* is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. | |||||
*/ | |||||
package me.chanjar.weixin.common.util.json; | package me.chanjar.weixin.common.util.json; | ||||
import com.google.gson.*; | import com.google.gson.*; | ||||
@@ -46,8 +46,7 @@ import java.util.*; | |||||
*/ | */ | ||||
public class StringManager { | public class StringManager { | ||||
private static final Map<String, Map<Locale, StringManager>> managers = | |||||
new Hashtable<>(); | |||||
private static final Map<String, Map<Locale, StringManager>> MANAGERS = new Hashtable<>(); | |||||
private static int LOCALE_CACHE_SIZE = 10; | private static int LOCALE_CACHE_SIZE = 10; | ||||
/** | /** | ||||
* The ResourceBundle for this StringManager. | * The ResourceBundle for this StringManager. | ||||
@@ -118,16 +117,16 @@ public class StringManager { | |||||
public static final synchronized StringManager getManager( | public static final synchronized StringManager getManager( | ||||
String packageName, Locale locale) { | String packageName, Locale locale) { | ||||
Map<Locale, StringManager> map = managers.get(packageName); | |||||
Map<Locale, StringManager> map = MANAGERS.get(packageName); | |||||
if (map == null) { | if (map == null) { | ||||
/* | |||||
* Don't want the HashMap to be expanded beyond LOCALE_CACHE_SIZE. | |||||
* Expansion occurs when size() exceeds capacity. Therefore keep | |||||
* size at or below capacity. | |||||
* removeEldestEntry() executes after insertion therefore the test | |||||
* for removal needs to use one less than the maximum desired size | |||||
* | |||||
*/ | |||||
/* | |||||
* Don't want the HashMap to be expanded beyond LOCALE_CACHE_SIZE. | |||||
* Expansion occurs when size() exceeds capacity. Therefore keep | |||||
* size at or below capacity. | |||||
* removeEldestEntry() executes after insertion therefore the test | |||||
* for removal needs to use one less than the maximum desired size | |||||
* | |||||
*/ | |||||
map = new LinkedHashMap<Locale, StringManager>(LOCALE_CACHE_SIZE, 1, true) { | map = new LinkedHashMap<Locale, StringManager>(LOCALE_CACHE_SIZE, 1, true) { | ||||
private static final long serialVersionUID = 1L; | private static final long serialVersionUID = 1L; | ||||
@@ -137,7 +136,7 @@ public class StringManager { | |||||
return size() > (LOCALE_CACHE_SIZE - 1); | return size() > (LOCALE_CACHE_SIZE - 1); | ||||
} | } | ||||
}; | }; | ||||
managers.put(packageName, map); | |||||
MANAGERS.put(packageName, map); | |||||
} | } | ||||
StringManager mgr = map.get(locale); | StringManager mgr = map.get(locale); | ||||
@@ -1,6 +1,7 @@ | |||||
package me.chanjar.weixin.common.util.xml; | package me.chanjar.weixin.common.util.xml; | ||||
import com.thoughtworks.xstream.XStream; | import com.thoughtworks.xstream.XStream; | ||||
import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; | |||||
import com.thoughtworks.xstream.core.util.QuickWriter; | import com.thoughtworks.xstream.core.util.QuickWriter; | ||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter; | import com.thoughtworks.xstream.io.HierarchicalStreamWriter; | ||||
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; | import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; | ||||
@@ -13,7 +14,7 @@ import java.io.Writer; | |||||
public class XStreamInitializer { | public class XStreamInitializer { | ||||
public static XStream getInstance() { | public static XStream getInstance() { | ||||
XStream xstream = new XStream(new XppDriver() { | |||||
XStream xstream = new XStream(new PureJavaReflectionProvider(), new XppDriver() { | |||||
@Override | @Override | ||||
public HierarchicalStreamWriter createWriter(Writer out) { | public HierarchicalStreamWriter createWriter(Writer out) { | ||||
@@ -42,6 +43,7 @@ public class XStreamInitializer { | |||||
}; | }; | ||||
} | } | ||||
}); | }); | ||||
xstream.ignoreUnknownElements(); | xstream.ignoreUnknownElements(); | ||||
xstream.setMode(XStream.NO_REFERENCES); | xstream.setMode(XStream.NO_REFERENCES); | ||||
xstream.addPermission(NullPermission.NULL); | xstream.addPermission(NullPermission.NULL); | ||||
@@ -3,15 +3,17 @@ package me.chanjar.weixin.common.api; | |||||
import org.testng.Assert; | import org.testng.Assert; | ||||
import org.testng.annotations.Test; | import org.testng.annotations.Test; | ||||
import java.util.concurrent.TimeUnit; | |||||
import static org.testng.Assert.assertFalse; | import static org.testng.Assert.assertFalse; | ||||
import static org.testng.Assert.assertTrue; | import static org.testng.Assert.assertTrue; | ||||
@Test | @Test | ||||
public class WxMessageInMemoryDuplicateCheckerTest { | public class WxMessageInMemoryDuplicateCheckerTest { | ||||
private WxMessageInMemoryDuplicateChecker checker = new WxMessageInMemoryDuplicateChecker(2000l, 1000l); | |||||
private WxMessageInMemoryDuplicateChecker checker = new WxMessageInMemoryDuplicateChecker(2000L, 1000L); | |||||
public void test() throws InterruptedException { | public void test() throws InterruptedException { | ||||
Long[] msgIds = new Long[]{1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l}; | |||||
Long[] msgIds = new Long[]{1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L}; | |||||
// 第一次检查 | // 第一次检查 | ||||
for (Long msgId : msgIds) { | for (Long msgId : msgIds) { | ||||
@@ -20,14 +22,14 @@ public class WxMessageInMemoryDuplicateCheckerTest { | |||||
} | } | ||||
// 过1秒再检查 | // 过1秒再检查 | ||||
Thread.sleep(1000l); | |||||
TimeUnit.SECONDS.sleep(1); | |||||
for (Long msgId : msgIds) { | for (Long msgId : msgIds) { | ||||
boolean result = checker.isDuplicate(String.valueOf(msgId)); | boolean result = checker.isDuplicate(String.valueOf(msgId)); | ||||
assertTrue(result); | assertTrue(result); | ||||
} | } | ||||
// 过1.5秒再检查 | // 过1.5秒再检查 | ||||
Thread.sleep(1500l); | |||||
TimeUnit.MILLISECONDS.sleep(1500L); | |||||
for (Long msgId : msgIds) { | for (Long msgId : msgIds) { | ||||
boolean result = checker.isDuplicate(String.valueOf(msgId)); | boolean result = checker.isDuplicate(String.valueOf(msgId)); | ||||
assertFalse(result); | assertFalse(result); | ||||
@@ -80,7 +80,7 @@ public class SessionTest { | |||||
InternalSession abc = ism.createSession("abc"); | InternalSession abc = ism.createSession("abc"); | ||||
abc.endAccess(); | abc.endAccess(); | ||||
Thread.sleep(2000l); | |||||
Thread.sleep(2000); | |||||
Assert.assertEquals(ism.getActiveSessions(), 0); | Assert.assertEquals(ism.getActiveSessions(), 0); | ||||
} | } | ||||
@@ -99,7 +99,7 @@ public class SessionTest { | |||||
abc.setMaxInactiveInterval(1); | abc.setMaxInactiveInterval(1); | ||||
abc.endAccess(); | abc.endAccess(); | ||||
Thread.sleep(2000l); | |||||
Thread.sleep(2000); | |||||
Assert.assertEquals(ism.getActiveSessions(), 0); | Assert.assertEquals(ism.getActiveSessions(), 0); | ||||
} | } | ||||
@@ -7,11 +7,11 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>weixin-java-parent</artifactId> | <artifactId>weixin-java-parent</artifactId> | ||||
<version>2.9.0</version> | |||||
<version>2.9.9.BETA</version> | |||||
</parent> | </parent> | ||||
<artifactId>weixin-java-cp</artifactId> | <artifactId>weixin-java-cp</artifactId> | ||||
<name>WeiXin Java Tools - CP</name> | |||||
<name>Weixin Java Tools - CP</name> | |||||
<description>微信企业号Java SDK</description> | <description>微信企业号Java SDK</description> | ||||
<dependencies> | <dependencies> | ||||
@@ -69,6 +69,16 @@ | |||||
<artifactId>logback-classic</artifactId> | <artifactId>logback-classic</artifactId> | ||||
<scope>test</scope> | <scope>test</scope> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>org.projectlombok</groupId> | |||||
<artifactId>lombok</artifactId> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.assertj</groupId> | |||||
<artifactId>assertj-guava</artifactId> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
<build> | <build> | ||||
@@ -29,11 +29,12 @@ public interface WxCpDepartmentService { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 部门管理接口 - 查询所有部门 | |||||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口 | |||||
* 部门管理接口 - 查询部门 | |||||
* 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E5.88.97.E8.A1.A8 | |||||
* </pre> | * </pre> | ||||
* @param id 部门id。获取指定部门及其下的子部门。非必需,可为null | |||||
*/ | */ | ||||
List<WxCpDepart> listAll() throws WxErrorException; | |||||
List<WxCpDepart> list(Integer id) throws WxErrorException; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
@@ -19,9 +19,9 @@ import java.util.List; | |||||
/** | /** | ||||
* 微信API的Service | * 微信API的Service | ||||
* @author chanjaster | |||||
*/ | */ | ||||
public interface WxCpService { | public interface WxCpService { | ||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 验证推送过来的消息的正确性 | * 验证推送过来的消息的正确性 | ||||
@@ -85,42 +85,6 @@ public interface WxCpService { | |||||
*/ | */ | ||||
WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; | WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; | ||||
/** | |||||
* @deprecated 请使用 {@link WxCpMenuService#create(WxMenu)} | |||||
*/ | |||||
@Deprecated | |||||
void menuCreate(WxMenu menu) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpMenuService#create(Integer, WxMenu)} | |||||
*/ | |||||
@Deprecated | |||||
void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpMenuService#delete()} } | |||||
*/ | |||||
@Deprecated | |||||
void menuDelete() throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpMenuService#delete(Integer)} | |||||
*/ | |||||
@Deprecated | |||||
void menuDelete(Integer agentId) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpMenuService#get() } | |||||
*/ | |||||
@Deprecated | |||||
WxMenu menuGet() throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpMenuService#get(Integer)} | |||||
*/ | |||||
@Deprecated | |||||
WxMenu menuGet(Integer agentId) throws WxErrorException; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 发送消息 | * 发送消息 | ||||
@@ -131,175 +95,6 @@ public interface WxCpService { | |||||
*/ | */ | ||||
WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorException; | WxCpMessageSendResult messageSend(WxCpMessage message) throws WxErrorException; | ||||
/** | |||||
* @deprecated 请使用 {@link WxCpDepartmentService#create(WxCpDepart)} | |||||
*/ | |||||
@Deprecated | |||||
Integer departCreate(WxCpDepart depart) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpDepartmentService#update(WxCpDepart)} | |||||
*/ | |||||
@Deprecated | |||||
void departUpdate(WxCpDepart group) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpDepartmentService#delete(Integer)} | |||||
*/ | |||||
@Deprecated | |||||
void departDelete(Integer departId) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpDepartmentService#listAll() } | |||||
*/ | |||||
@Deprecated | |||||
List<WxCpDepart> departGet() throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpMediaService#upload(String, String, InputStream)} | |||||
*/ | |||||
@Deprecated | |||||
WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) | |||||
throws WxErrorException, IOException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpMediaService#upload(String, File)} | |||||
*/ | |||||
@Deprecated | |||||
WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpMediaService#download(String)} | |||||
*/ | |||||
@Deprecated | |||||
File mediaDownload(String mediaId) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpUserService#authenticate(String)} | |||||
*/ | |||||
@Deprecated | |||||
void userAuthenticated(String userId) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpUserService#create(WxCpUser)} | |||||
*/ | |||||
@Deprecated | |||||
void userCreate(WxCpUser user) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpUserService#update(WxCpUser)} | |||||
*/ | |||||
@Deprecated | |||||
void userUpdate(WxCpUser user) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpUserService#delete(String...)} | |||||
*/ | |||||
@Deprecated | |||||
void userDelete(String userid) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpUserService#delete(String...)} | |||||
*/ | |||||
@Deprecated | |||||
void userDelete(String[] userids) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpUserService#getById(String)} | |||||
*/ | |||||
@Deprecated | |||||
WxCpUser userGet(String userid) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpUserService#listByDepartment(Integer, Boolean, Integer)} | |||||
*/ | |||||
@Deprecated | |||||
List<WxCpUser> userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpUserService#listSimpleByDepartment(Integer, Boolean, Integer)} | |||||
*/ | |||||
@Deprecated | |||||
List<WxCpUser> departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpTagService#create(String)} | |||||
*/ | |||||
@Deprecated | |||||
String tagCreate(String tagName) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpTagService#update(String, String)} | |||||
*/ | |||||
@Deprecated | |||||
void tagUpdate(String tagId, String tagName) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpTagService#delete(String)} | |||||
*/ | |||||
@Deprecated | |||||
void tagDelete(String tagId) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpTagService#listAll()} | |||||
*/ | |||||
@Deprecated | |||||
List<WxCpTag> tagGet() throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpTagService#listUsersByTagId(String)} | |||||
*/ | |||||
@Deprecated | |||||
List<WxCpUser> tagGetUsers(String tagId) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpTagService#addUsers2Tag(String, List, List)} | |||||
*/ | |||||
@Deprecated | |||||
void tagAddUsers(String tagId, List<String> userIds, List<String> partyIds) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpTagService#removeUsersFromTag(String, List)} | |||||
*/ | |||||
@Deprecated | |||||
void tagRemoveUsers(String tagId, List<String> userIds) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpOAuth2Service#buildAuthorizationUrl(String)} | |||||
*/ | |||||
@Deprecated | |||||
String oauth2buildAuthorizationUrl(String state); | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpOAuth2Service#buildAuthorizationUrl(String, String)} | |||||
*/ | |||||
@Deprecated | |||||
String oauth2buildAuthorizationUrl(String redirectUri, String state); | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpOAuth2Service#getUserInfo(String)} | |||||
*/ | |||||
@Deprecated | |||||
String[] oauth2getUserInfo(String code) throws WxErrorException; | |||||
/** | |||||
* @deprecated 请使用 {@link WxCpOAuth2Service#getUserInfo(Integer, String)} | |||||
*/ | |||||
@Deprecated | |||||
String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException; | |||||
/** | |||||
* <pre> | |||||
* 邀请成员关注 | |||||
* http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E9.82.80.E8.AF.B7.E6.88.90.E5.91.98.E5.85.B3.E6.B3.A8 | |||||
* </pre> | |||||
* | |||||
* @param userId 用户的userid | |||||
* @param inviteTips 推送到微信上的提示语(只有认证号可以使用)。当使用微信推送时,该字段默认为“请关注XXX企业号”,邮件邀请时,该字段无效。 | |||||
* @return 1:微信邀请 2.邮件邀请 | |||||
*/ | |||||
int invite(String userId, String inviteTips) throws WxErrorException; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 获取微信服务器的ip段 | * 获取微信服务器的ip段 | ||||
@@ -4,6 +4,7 @@ import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.cp.bean.WxCpUser; | import me.chanjar.weixin.cp.bean.WxCpUser; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
@@ -80,4 +81,56 @@ public interface WxCpUserService { | |||||
* @param userid 用户id | * @param userid 用户id | ||||
*/ | */ | ||||
WxCpUser getById(String userid) throws WxErrorException; | WxCpUser getById(String userid) throws WxErrorException; | ||||
/** | |||||
* <pre> | |||||
* 邀请成员关注 | |||||
* http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E9.82.80.E8.AF.B7.E6.88.90.E5.91.98.E5.85.B3.E6.B3.A8 | |||||
* </pre> | |||||
* | |||||
* @param userId 用户的userid | |||||
* @param inviteTips 推送到微信上的提示语(只有认证号可以使用)。当使用微信推送时,该字段默认为“请关注XXX企业号”,邮件邀请时,该字段无效。 | |||||
* @return 1:微信邀请 2.邮件邀请 | |||||
* @deprecated api obsoleted. 邀请关注的功能微信企业号已经下线了, | |||||
* 详细请参考该链接点击查看 https://qy.weixin.qq.com/cgi-bin/homepagenotify?action=get&id=46 | |||||
*/ | |||||
@Deprecated | |||||
int invite(String userId, String inviteTips) throws WxErrorException; | |||||
/** | |||||
* <pre> | |||||
* userid转openid. | |||||
* 该接口使用场景为微信支付、微信红包和企业转账。 | |||||
* | |||||
* 在使用微信支付的功能时,需要自行将企业微信的userid转成openid。 | |||||
* 在使用微信红包功能时,需要将应用id和userid转成appid和openid才能使用。 | |||||
* 注:需要成员使用微信登录企业微信或者关注微信插件才能转成openid | |||||
* | |||||
* 文档地址:https://work.weixin.qq.com/api/doc#11279 | |||||
* </pre> | |||||
* | |||||
* @param userId 企业内的成员id | |||||
* @param agentId 非必填,整型,仅用于发红包。其它场景该参数不要填,如微信支付、企业转账、电子发票 | |||||
* @return map对象,可能包含以下值: | |||||
* - openid 企业微信成员userid对应的openid,若有传参agentid,则是针对该agentid的openid。否则是针对企业微信corpid的openid | |||||
* - appid 应用的appid,若请求包中不包含agentid则不返回appid。该appid在使用微信红包时会用到 | |||||
*/ | |||||
Map<String, String> userId2Openid(String userId, Integer agentId) throws WxErrorException; | |||||
/** | |||||
* <pre> | |||||
* openid转userid | |||||
* | |||||
* 该接口主要应用于使用微信支付、微信红包和企业转账之后的结果查询。 | |||||
* 开发者需要知道某个结果事件的openid对应企业微信内成员的信息时,可以通过调用该接口进行转换查询。 | |||||
* 权限说明: | |||||
* 管理组需对openid对应的企业微信成员有查看权限。 | |||||
* | |||||
* 文档地址:https://work.weixin.qq.com/api/doc#11279 | |||||
* </pre> | |||||
* | |||||
* @param openid 在使用微信支付、微信红包和企业转账之后,返回结果的openid | |||||
* @return userid 该openid在企业微信对应的成员userid | |||||
*/ | |||||
String openid2UserId(String openid) throws WxErrorException; | |||||
} | } |
@@ -48,13 +48,13 @@ public class WxCpDepartmentServiceImpl implements WxCpDepartmentService { | |||||
} | } | ||||
@Override | @Override | ||||
public List<WxCpDepart> listAll() throws WxErrorException { | |||||
public List<WxCpDepart> list(Integer id) throws WxErrorException { | |||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; | String url = "https://qyapi.weixin.qq.com/cgi-bin/department/list"; | ||||
if (id != null) { | |||||
url += "?id=" + id; | |||||
} | |||||
String responseContent = this.mainService.get(url, null); | String responseContent = this.mainService.get(url, null); | ||||
/* | |||||
* 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} } | |||||
* 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] } | |||||
*/ | |||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | ||||
return WxCpGsonBuilder.INSTANCE.create() | return WxCpGsonBuilder.INSTANCE.create() | ||||
.fromJson(tmpJsonElement.getAsJsonObject().get("department"), | .fromJson(tmpJsonElement.getAsJsonObject().get("department"), | ||||
@@ -47,7 +47,7 @@ public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service { | |||||
@Override | @Override | ||||
public String[] getUserInfo(String code) throws WxErrorException { | public String[] getUserInfo(String code) throws WxErrorException { | ||||
return getUserInfo(this.mainService.getWxCpConfigStorage().getAgentId(), code); | |||||
return this.getUserInfo(this.mainService.getWxCpConfigStorage().getAgentId(), code); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -138,188 +138,6 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ | |||||
return WxCpMessageSendResult.fromJson(this.post(url, message.toJson())); | return WxCpMessageSendResult.fromJson(this.post(url, message.toJson())); | ||||
} | } | ||||
@Override | |||||
@Deprecated | |||||
public void menuCreate(WxMenu menu) throws WxErrorException { | |||||
this.getMenuService().create(menu); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void menuCreate(Integer agentId, WxMenu menu) throws WxErrorException { | |||||
this.getMenuService().create(agentId, menu); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void menuDelete() throws WxErrorException { | |||||
this.getMenuService().delete(); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void menuDelete(Integer agentId) throws WxErrorException { | |||||
this.getMenuService().delete(agentId); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public WxMenu menuGet() throws WxErrorException { | |||||
return this.getMenuService().get(); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public WxMenu menuGet(Integer agentId) throws WxErrorException { | |||||
return this.getMenuService().get(agentId); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) | |||||
throws WxErrorException, IOException { | |||||
return this.getMediaService().upload(mediaType, fileType, inputStream); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { | |||||
return this.getMediaService().upload(mediaType, file); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public File mediaDownload(String mediaId) throws WxErrorException { | |||||
return this.getMediaService().download(mediaId); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void userAuthenticated(String userId) throws WxErrorException { | |||||
this.getUserService().authenticate(userId); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void userCreate(WxCpUser user) throws WxErrorException { | |||||
this.getUserService().create(user); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void userUpdate(WxCpUser user) throws WxErrorException { | |||||
this.getUserService().update(user); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void userDelete(String userid) throws WxErrorException { | |||||
this.getUserService().delete(userid); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void userDelete(String[] userids) throws WxErrorException { | |||||
this.getUserService().delete(userids); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public WxCpUser userGet(String userid) throws WxErrorException { | |||||
return this.getUserService().getById(userid); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public List<WxCpUser> userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { | |||||
return this.getUserService().listByDepartment(departId, fetchChild, status); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public List<WxCpUser> departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException { | |||||
return this.getUserService().listSimpleByDepartment(departId, fetchChild, status); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public String tagCreate(String tagName) throws WxErrorException { | |||||
return this.getTagService().create(tagName); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void tagUpdate(String tagId, String tagName) throws WxErrorException { | |||||
this.getTagService().update(tagId, tagName); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void tagDelete(String tagId) throws WxErrorException { | |||||
this.getTagService().delete(tagId); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public List<WxCpTag> tagGet() throws WxErrorException { | |||||
return this.getTagService().listAll(); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public List<WxCpUser> tagGetUsers(String tagId) throws WxErrorException { | |||||
return this.getTagService().listUsersByTagId(tagId); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void tagAddUsers(String tagId, List<String> userIds, List<String> partyIds) throws WxErrorException { | |||||
this.getTagService().addUsers2Tag(tagId, userIds, partyIds); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void tagRemoveUsers(String tagId, List<String> userIds) throws WxErrorException { | |||||
this.getTagService().removeUsersFromTag(tagId, userIds); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public String oauth2buildAuthorizationUrl(String state) { | |||||
return this.getOauth2Service().buildAuthorizationUrl(state); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public String oauth2buildAuthorizationUrl(String redirectUri, String state) { | |||||
return this.getOauth2Service().buildAuthorizationUrl(redirectUri, state); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public String[] oauth2getUserInfo(String code) throws WxErrorException { | |||||
return this.getOauth2Service().getUserInfo(code); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public String[] oauth2getUserInfo(Integer agentId, String code) throws WxErrorException { | |||||
return this.getOauth2Service().getUserInfo(agentId, code); | |||||
} | |||||
@Override | |||||
public int invite(String userId, String inviteTips) throws WxErrorException { | |||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/invite/send"; | |||||
JsonObject jsonObject = new JsonObject(); | |||||
jsonObject.addProperty("userid", userId); | |||||
if (StringUtils.isNotEmpty(inviteTips)) { | |||||
jsonObject.addProperty("invite_tips", inviteTips); | |||||
} | |||||
String responseContent = post(url, jsonObject.toString()); | |||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | |||||
return tmpJsonElement.getAsJsonObject().get("type").getAsInt(); | |||||
} | |||||
@Override | @Override | ||||
public String[] getCallbackIp() throws WxErrorException { | public String[] getCallbackIp() throws WxErrorException { | ||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/getcallbackip"; | String url = "https://qyapi.weixin.qq.com/cgi-bin/getcallbackip"; | ||||
@@ -516,30 +334,6 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ | |||||
return userService; | return userService; | ||||
} | } | ||||
@Override | |||||
@Deprecated | |||||
public Integer departCreate(WxCpDepart depart) throws WxErrorException { | |||||
return this.getDepartmentService().create(depart); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void departUpdate(WxCpDepart depart) throws WxErrorException { | |||||
this.getDepartmentService().update(depart); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public void departDelete(Integer departId) throws WxErrorException { | |||||
this.getDepartmentService().delete(departId); | |||||
} | |||||
@Override | |||||
@Deprecated | |||||
public List<WxCpDepart> departGet() throws WxErrorException { | |||||
return this.getDepartmentService().listAll(); | |||||
} | |||||
@Override | @Override | ||||
public RequestHttp getRequestHttp() { | public RequestHttp getRequestHttp() { | ||||
return this; | return this; | ||||
@@ -1,5 +1,6 @@ | |||||
package me.chanjar.weixin.cp.api.impl; | package me.chanjar.weixin.cp.api.impl; | ||||
import com.google.common.collect.Maps; | |||||
import com.google.gson.*; | import com.google.gson.*; | ||||
import com.google.gson.reflect.TypeToken; | import com.google.gson.reflect.TypeToken; | ||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
@@ -7,8 +8,10 @@ import me.chanjar.weixin.cp.api.WxCpService; | |||||
import me.chanjar.weixin.cp.api.WxCpUserService; | import me.chanjar.weixin.cp.api.WxCpUserService; | ||||
import me.chanjar.weixin.cp.bean.WxCpUser; | import me.chanjar.weixin.cp.bean.WxCpUser; | ||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
import org.apache.commons.lang3.StringUtils; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
@@ -112,4 +115,50 @@ public class WxCpUserServiceImpl implements WxCpUserService { | |||||
); | ); | ||||
} | } | ||||
@Override | |||||
@Deprecated | |||||
public int invite(String userId, String inviteTips) throws WxErrorException { | |||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/invite/send"; | |||||
JsonObject jsonObject = new JsonObject(); | |||||
jsonObject.addProperty("userid", userId); | |||||
if (StringUtils.isNotEmpty(inviteTips)) { | |||||
jsonObject.addProperty("invite_tips", inviteTips); | |||||
} | |||||
String responseContent = this.mainService.post(url, jsonObject.toString()); | |||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | |||||
return tmpJsonElement.getAsJsonObject().get("type").getAsInt(); | |||||
} | |||||
@Override | |||||
public Map<String, String> userId2Openid(String userId, Integer agentId) throws WxErrorException { | |||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_openid"; | |||||
JsonObject jsonObject = new JsonObject(); | |||||
jsonObject.addProperty("userid", userId); | |||||
if (agentId != null) { | |||||
jsonObject.addProperty("agentid", agentId); | |||||
} | |||||
String responseContent = this.mainService.post(url, jsonObject.toString()); | |||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | |||||
Map<String, String> result = Maps.newHashMap(); | |||||
if (tmpJsonElement.getAsJsonObject().get("openid") != null) { | |||||
result.put("openid", tmpJsonElement.getAsJsonObject().get("openid").getAsString()); | |||||
} | |||||
if (tmpJsonElement.getAsJsonObject().get("appid") != null) { | |||||
result.put("appid", tmpJsonElement.getAsJsonObject().get("appid").getAsString()); | |||||
} | |||||
return result; | |||||
} | |||||
@Override | |||||
public String openid2UserId(String openid) throws WxErrorException { | |||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_userid"; | |||||
JsonObject jsonObject = new JsonObject(); | |||||
jsonObject.addProperty("openid", openid); | |||||
String responseContent = this.mainService.post(url, jsonObject.toString()); | |||||
JsonElement tmpJsonElement = new JsonParser().parse(responseContent); | |||||
return tmpJsonElement.getAsJsonObject().get("userid").getAsString(); | |||||
} | |||||
} | } |
@@ -16,8 +16,14 @@ import java.util.List; | |||||
@Data | @Data | ||||
public class WxCpUser implements Serializable { | public class WxCpUser implements Serializable { | ||||
public enum Gender { | public enum Gender { | ||||
/** | |||||
* 男 | |||||
*/ | |||||
MALE("男", "1"), | MALE("男", "1"), | ||||
FEMAIL("女", "2"); | |||||
/** | |||||
* 女 | |||||
*/ | |||||
FEMALE("女", "2"); | |||||
private String genderName; | private String genderName; | ||||
private String code; | private String code; | ||||
@@ -40,7 +46,7 @@ public class WxCpUser implements Serializable { | |||||
return Gender.MALE; | return Gender.MALE; | ||||
} | } | ||||
if ("2".equals(code)) { | if ("2".equals(code)) { | ||||
return Gender.FEMAIL; | |||||
return Gender.FEMALE; | |||||
} | } | ||||
return null; | return null; | ||||
@@ -3,11 +3,13 @@ package me.chanjar.weixin.cp.bean; | |||||
import com.thoughtworks.xstream.annotations.XStreamAlias; | import com.thoughtworks.xstream.annotations.XStreamAlias; | ||||
import com.thoughtworks.xstream.annotations.XStreamConverter; | import com.thoughtworks.xstream.annotations.XStreamConverter; | ||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.EqualsAndHashCode; | |||||
import me.chanjar.weixin.common.api.WxConsts; | import me.chanjar.weixin.common.api.WxConsts; | ||||
import me.chanjar.weixin.common.util.xml.XStreamMediaIdConverter; | import me.chanjar.weixin.common.util.xml.XStreamMediaIdConverter; | ||||
@XStreamAlias("xml") | @XStreamAlias("xml") | ||||
@Data | @Data | ||||
@EqualsAndHashCode(callSuper = false) | |||||
public class WxCpXmlOutImageMessage extends WxCpXmlOutMessage { | public class WxCpXmlOutImageMessage extends WxCpXmlOutMessage { | ||||
private static final long serialVersionUID = -1099446240667237313L; | private static final long serialVersionUID = -1099446240667237313L; | ||||
@@ -3,11 +3,13 @@ package me.chanjar.weixin.cp.bean; | |||||
import com.thoughtworks.xstream.annotations.XStreamAlias; | import com.thoughtworks.xstream.annotations.XStreamAlias; | ||||
import com.thoughtworks.xstream.annotations.XStreamConverter; | import com.thoughtworks.xstream.annotations.XStreamConverter; | ||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.EqualsAndHashCode; | |||||
import me.chanjar.weixin.common.api.WxConsts; | import me.chanjar.weixin.common.api.WxConsts; | ||||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | ||||
@XStreamAlias("xml") | @XStreamAlias("xml") | ||||
@Data | @Data | ||||
@EqualsAndHashCode(callSuper = false) | |||||
public class WxCpXmlOutTextMessage extends WxCpXmlOutMessage { | public class WxCpXmlOutTextMessage extends WxCpXmlOutMessage { | ||||
private static final long serialVersionUID = 2569239617185930232L; | private static final long serialVersionUID = 2569239617185930232L; | ||||
@@ -3,11 +3,13 @@ package me.chanjar.weixin.cp.bean; | |||||
import com.thoughtworks.xstream.annotations.XStreamAlias; | import com.thoughtworks.xstream.annotations.XStreamAlias; | ||||
import com.thoughtworks.xstream.annotations.XStreamConverter; | import com.thoughtworks.xstream.annotations.XStreamConverter; | ||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.EqualsAndHashCode; | |||||
import me.chanjar.weixin.common.api.WxConsts; | import me.chanjar.weixin.common.api.WxConsts; | ||||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | ||||
@XStreamAlias("xml") | @XStreamAlias("xml") | ||||
@Data | @Data | ||||
@EqualsAndHashCode(callSuper = false) | |||||
public class WxCpXmlOutVideoMessage extends WxCpXmlOutMessage { | public class WxCpXmlOutVideoMessage extends WxCpXmlOutMessage { | ||||
private static final long serialVersionUID = -8672761162722733622L; | private static final long serialVersionUID = -8672761162722733622L; | ||||
@@ -3,11 +3,13 @@ package me.chanjar.weixin.cp.bean; | |||||
import com.thoughtworks.xstream.annotations.XStreamAlias; | import com.thoughtworks.xstream.annotations.XStreamAlias; | ||||
import com.thoughtworks.xstream.annotations.XStreamConverter; | import com.thoughtworks.xstream.annotations.XStreamConverter; | ||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.EqualsAndHashCode; | |||||
import me.chanjar.weixin.common.api.WxConsts; | import me.chanjar.weixin.common.api.WxConsts; | ||||
import me.chanjar.weixin.common.util.xml.XStreamMediaIdConverter; | import me.chanjar.weixin.common.util.xml.XStreamMediaIdConverter; | ||||
@XStreamAlias("xml") | @XStreamAlias("xml") | ||||
@Data | @Data | ||||
@EqualsAndHashCode(callSuper = false) | |||||
public class WxCpXmlOutVoiceMessage extends WxCpXmlOutMessage { | public class WxCpXmlOutVoiceMessage extends WxCpXmlOutMessage { | ||||
private static final long serialVersionUID = -7947384031546099340L; | private static final long serialVersionUID = -7947384031546099340L; | ||||
@@ -23,7 +23,7 @@ public abstract class BaseBuilder<BuilderType, ValueType> { | |||||
public void setCommon(WxCpXmlOutMessage m) { | public void setCommon(WxCpXmlOutMessage m) { | ||||
m.setToUserName(this.toUserName); | m.setToUserName(this.toUserName); | ||||
m.setFromUserName(this.fromUserName); | m.setFromUserName(this.fromUserName); | ||||
m.setCreateTime(System.currentTimeMillis() / 1000l); | |||||
m.setCreateTime(System.currentTimeMillis() / 1000L); | |||||
} | } | ||||
} | } |
@@ -63,7 +63,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { | |||||
@Override | @Override | ||||
public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { | public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { | ||||
this.accessToken = accessToken; | this.accessToken = accessToken; | ||||
this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; | |||||
this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; | |||||
} | } | ||||
@Override | @Override | ||||
@@ -92,7 +92,7 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { | |||||
public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { | public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { | ||||
this.jsapiTicket = jsapiTicket; | this.jsapiTicket = jsapiTicket; | ||||
// 预留200秒的时间 | // 预留200秒的时间 | ||||
this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l; | |||||
this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; | |||||
} | } | ||||
@Override | @Override | ||||
@@ -19,12 +19,16 @@ import java.io.File; | |||||
*/ | */ | ||||
public class WxCpJedisConfigStorage implements WxCpConfigStorage { | public class WxCpJedisConfigStorage implements WxCpConfigStorage { | ||||
/* Redis keys here */ | |||||
/** | |||||
* Redis keys here | |||||
*/ | |||||
private static final String ACCESS_TOKEN_KEY = "WX_CP_ACCESS_TOKEN"; | private static final String ACCESS_TOKEN_KEY = "WX_CP_ACCESS_TOKEN"; | ||||
private static final String ACCESS_TOKEN_EXPIRES_TIME_KEY = "WX_CP_ACCESS_TOKEN_EXPIRES_TIME"; | private static final String ACCESS_TOKEN_EXPIRES_TIME_KEY = "WX_CP_ACCESS_TOKEN_EXPIRES_TIME"; | ||||
private static final String JS_API_TICKET_KEY = "WX_CP_JS_API_TICKET"; | private static final String JS_API_TICKET_KEY = "WX_CP_JS_API_TICKET"; | ||||
private static final String JS_API_TICKET_EXPIRES_TIME_KEY = "WX_CP_JS_API_TICKET_EXPIRES_TIME"; | private static final String JS_API_TICKET_EXPIRES_TIME_KEY = "WX_CP_JS_API_TICKET_EXPIRES_TIME"; | ||||
/* Redis clients pool */ | |||||
/** | |||||
* Redis clients pool | |||||
*/ | |||||
private final JedisPool jedisPool; | private final JedisPool jedisPool; | ||||
private volatile String corpId; | private volatile String corpId; | ||||
private volatile String corpSecret; | private volatile String corpSecret; | ||||
@@ -196,8 +200,7 @@ public class WxCpJedisConfigStorage implements WxCpConfigStorage { | |||||
String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY); | String expiresTimeStr = jedis.get(ACCESS_TOKEN_EXPIRES_TIME_KEY); | ||||
if (expiresTimeStr != null) { | if (expiresTimeStr != null) { | ||||
Long expiresTime = Long.parseLong(expiresTimeStr); | |||||
return expiresTime; | |||||
return Long.parseLong(expiresTimeStr); | |||||
} | } | ||||
return 0L; | return 0L; | ||||
@@ -1,13 +1,19 @@ | |||||
package me.chanjar.weixin.cp.util.xml; | package me.chanjar.weixin.cp.util.xml; | ||||
import com.thoughtworks.xstream.XStream; | |||||
import me.chanjar.weixin.common.util.xml.XStreamInitializer; | |||||
import me.chanjar.weixin.cp.bean.*; | |||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Map; | import java.util.Map; | ||||
import com.thoughtworks.xstream.XStream; | |||||
import me.chanjar.weixin.common.util.xml.XStreamInitializer; | |||||
import me.chanjar.weixin.cp.bean.WxCpXmlMessage; | |||||
import me.chanjar.weixin.cp.bean.WxCpXmlOutImageMessage; | |||||
import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; | |||||
import me.chanjar.weixin.cp.bean.WxCpXmlOutNewsMessage; | |||||
import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; | |||||
import me.chanjar.weixin.cp.bean.WxCpXmlOutVideoMessage; | |||||
import me.chanjar.weixin.cp.bean.WxCpXmlOutVoiceMessage; | |||||
public class XStreamTransformer { | public class XStreamTransformer { | ||||
protected static final Map<Class, XStream> CLASS_2_XSTREAM_INSTANCE = configXStreamInstance(); | protected static final Map<Class, XStream> CLASS_2_XSTREAM_INSTANCE = configXStreamInstance(); | ||||
@@ -38,7 +44,7 @@ public class XStreamTransformer { | |||||
} | } | ||||
/** | /** | ||||
* pojo -> xml | |||||
* pojo -> xml. | |||||
*/ | */ | ||||
public static <T> String toXml(Class<T> clazz, T object) { | public static <T> String toXml(Class<T> clazz, T object) { | ||||
return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); | return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); | ||||
@@ -69,7 +69,7 @@ public class WxCpMessageRouterTest { | |||||
WxCpMessageRouter router = new WxCpMessageRouter(null); | WxCpMessageRouter router = new WxCpMessageRouter(null); | ||||
prepare(true, sb, router); | prepare(true, sb, router); | ||||
router.route(message); | router.route(message); | ||||
Thread.sleep(500l); | |||||
Thread.sleep(500); | |||||
Assert.assertEquals(sb.toString(), expected); | Assert.assertEquals(sb.toString(), expected); | ||||
} | } | ||||
@@ -89,7 +89,7 @@ public class WxCpMessageRouterTest { | |||||
public void run() { | public void run() { | ||||
router.route(m); | router.route(m); | ||||
try { | try { | ||||
Thread.sleep(1000l); | |||||
Thread.sleep(1000); | |||||
} catch (InterruptedException e) { | } catch (InterruptedException e) { | ||||
} | } | ||||
} | } | ||||
@@ -98,7 +98,7 @@ public class WxCpMessageRouterTest { | |||||
new Thread(r).start(); | new Thread(r).start(); | ||||
} | } | ||||
Thread.sleep(1000l * 2); | |||||
Thread.sleep(2000); | |||||
} | } | ||||
@DataProvider(name = "messages-1") | @DataProvider(name = "messages-1") | ||||
@@ -184,7 +184,7 @@ public class WxCpMessageRouterTest { | |||||
msg.setFromUserName("abc"); | msg.setFromUserName("abc"); | ||||
router.route(msg); | router.route(msg); | ||||
Thread.sleep(2000l); | |||||
Thread.sleep(2000); | |||||
Assert.assertEquals(ism.getActiveSessions(), 0); | Assert.assertEquals(ism.getActiveSessions(), 0); | ||||
} | } | ||||
@@ -204,7 +204,7 @@ public class WxCpMessageRouterTest { | |||||
msg.setFromUserName("abc"); | msg.setFromUserName("abc"); | ||||
router.route(msg); | router.route(msg); | ||||
Thread.sleep(2000l); | |||||
Thread.sleep(2000); | |||||
Assert.assertEquals(ism.getActiveSessions(), 0); | Assert.assertEquals(ism.getActiveSessions(), 0); | ||||
} | } | ||||
{ | { | ||||
@@ -218,7 +218,7 @@ public class WxCpMessageRouterTest { | |||||
msg.setFromUserName("abc"); | msg.setFromUserName("abc"); | ||||
router.route(msg); | router.route(msg); | ||||
Thread.sleep(2000l); | |||||
Thread.sleep(2000); | |||||
Assert.assertEquals(ism.getActiveSessions(), 0); | Assert.assertEquals(ism.getActiveSessions(), 0); | ||||
} | } | ||||
@@ -238,7 +238,7 @@ public class WxCpMessageRouterTest { | |||||
msg.setFromUserName("abc"); | msg.setFromUserName("abc"); | ||||
router.route(msg); | router.route(msg); | ||||
Thread.sleep(2000l); | |||||
Thread.sleep(2000); | |||||
Assert.assertEquals(ism.getActiveSessions(), 0); | Assert.assertEquals(ism.getActiveSessions(), 0); | ||||
} | } | ||||
@@ -257,7 +257,7 @@ public class WxCpMessageRouterTest { | |||||
msg.setFromUserName("abc"); | msg.setFromUserName("abc"); | ||||
router.route(msg); | router.route(msg); | ||||
Thread.sleep(2000l); | |||||
Thread.sleep(2000); | |||||
Assert.assertEquals(ism.getActiveSessions(), 0); | Assert.assertEquals(ism.getActiveSessions(), 0); | ||||
} | } | ||||
@@ -271,7 +271,7 @@ public class WxCpMessageRouterTest { | |||||
msg.setFromUserName("abc"); | msg.setFromUserName("abc"); | ||||
router.route(msg); | router.route(msg); | ||||
Thread.sleep(2000l); | |||||
Thread.sleep(2000); | |||||
Assert.assertEquals(ism.getActiveSessions(), 0); | Assert.assertEquals(ism.getActiveSessions(), 0); | ||||
} | } | ||||
} | } | ||||
@@ -8,6 +8,7 @@ import org.testng.annotations.*; | |||||
import java.util.List; | import java.util.List; | ||||
import static org.assertj.core.api.Assertions.assertThat; | |||||
import static org.testng.Assert.*; | import static org.testng.Assert.*; | ||||
/** | /** | ||||
@@ -34,16 +35,24 @@ public class WxCpDepartmentServiceImplTest { | |||||
System.out.println(departId); | System.out.println(departId); | ||||
} | } | ||||
@Test | |||||
public void testListAll() throws Exception { | |||||
@DataProvider | |||||
public Object[][] departIds(){ | |||||
return new Object[][]{ | |||||
{null}, | |||||
{1}, | |||||
{5} | |||||
}; | |||||
} | |||||
@Test(dataProvider = "departIds") | |||||
public void testList(Integer id) throws Exception { | |||||
System.out.println("=================获取部门"); | System.out.println("=================获取部门"); | ||||
List<WxCpDepart> departList = this.wxCpService.getDepartmentService().listAll(); | |||||
assertNotNull(departList); | |||||
assertTrue(departList.size() > 0); | |||||
List<WxCpDepart> departList = this.wxCpService.getDepartmentService().list(id); | |||||
assertThat(departList).isNotEmpty(); | |||||
for (WxCpDepart g : departList) { | for (WxCpDepart g : departList) { | ||||
this.depart = g; | this.depart = g; | ||||
System.out.println(this.depart.getId() + ":" + this.depart.getName()); | System.out.println(this.depart.getId() + ":" + this.depart.getName()); | ||||
assertNotNull(g.getName()); | |||||
assertThat(g.getName()).isNotBlank(); | |||||
} | } | ||||
} | } | ||||
@@ -6,11 +6,14 @@ import me.chanjar.weixin.cp.api.WxCpService; | |||||
import me.chanjar.weixin.cp.bean.WxCpUser; | import me.chanjar.weixin.cp.bean.WxCpUser; | ||||
import org.apache.commons.lang3.builder.ToStringBuilder; | import org.apache.commons.lang3.builder.ToStringBuilder; | ||||
import org.apache.commons.lang3.builder.ToStringStyle; | import org.apache.commons.lang3.builder.ToStringStyle; | ||||
import org.testng.annotations.*; | |||||
import org.testng.annotations.Guice; | |||||
import org.testng.annotations.Test; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
import static org.testng.Assert.*; | |||||
import static org.testng.Assert.assertNotEquals; | |||||
import static org.testng.Assert.assertNotNull; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
@@ -37,7 +40,7 @@ public class WxCpUserServiceImplTest { | |||||
user.setName("Some Woman"); | user.setName("Some Woman"); | ||||
user.setDepartIds(new Integer[]{2}); | user.setDepartIds(new Integer[]{2}); | ||||
user.setEmail("none@none.com"); | user.setEmail("none@none.com"); | ||||
user.setGender(WxCpUser.Gender.FEMAIL); | |||||
user.setGender(WxCpUser.Gender.FEMALE); | |||||
user.setMobile("13560084979"); | user.setMobile("13560084979"); | ||||
user.setPosition("woman"); | user.setPosition("woman"); | ||||
user.setTelephone("3300393"); | user.setTelephone("3300393"); | ||||
@@ -83,4 +86,24 @@ public class WxCpUserServiceImplTest { | |||||
} | } | ||||
} | } | ||||
@Test | |||||
@Deprecated | |||||
public void testInvite() throws Exception { | |||||
int result = this.wxCpService.getUserService().invite(userId, ""); | |||||
System.out.println(result); | |||||
} | |||||
@Test | |||||
public void testUserId2Openid() throws Exception { | |||||
Map<String, String> result = this.wxCpService.getUserService().userId2Openid(userId, null); | |||||
System.out.println(result); | |||||
assertNotNull(result); | |||||
} | |||||
@Test | |||||
public void testOpenid2UserId() throws Exception { | |||||
String result = this.wxCpService.getUserService().openid2UserId(userId); | |||||
System.out.println(result); | |||||
assertNotNull(result); | |||||
} | |||||
} | } |
@@ -57,10 +57,10 @@ public class WxCpXmlMessageTest { | |||||
WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml); | WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml); | ||||
assertEquals(wxMessage.getToUserName(), "toUser"); | assertEquals(wxMessage.getToUserName(), "toUser"); | ||||
assertEquals(wxMessage.getFromUserName(), "fromUser"); | assertEquals(wxMessage.getFromUserName(), "fromUser"); | ||||
assertEquals(wxMessage.getCreateTime(), new Long(1348831860l)); | |||||
assertEquals(wxMessage.getCreateTime(), new Long(1348831860)); | |||||
assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.TEXT); | assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.TEXT); | ||||
assertEquals(wxMessage.getContent(), "this is a test"); | assertEquals(wxMessage.getContent(), "this is a test"); | ||||
assertEquals(wxMessage.getMsgId(), new Long(1234567890123456l)); | |||||
assertEquals(wxMessage.getMsgId(), new Long(1234567890123456L)); | |||||
assertEquals(wxMessage.getPicUrl(), "this is a url"); | assertEquals(wxMessage.getPicUrl(), "this is a url"); | ||||
assertEquals(wxMessage.getMediaId(), "media_id"); | assertEquals(wxMessage.getMediaId(), "media_id"); | ||||
assertEquals(wxMessage.getFormat(), "Format"); | assertEquals(wxMessage.getFormat(), "Format"); | ||||
@@ -80,7 +80,7 @@ public class WxCpXmlMessageTest { | |||||
assertEquals(wxMessage.getPrecision(), 119.385040); | assertEquals(wxMessage.getPrecision(), 119.385040); | ||||
assertEquals(wxMessage.getScanCodeInfo().getScanType(), "qrcode"); | assertEquals(wxMessage.getScanCodeInfo().getScanType(), "qrcode"); | ||||
assertEquals(wxMessage.getScanCodeInfo().getScanResult(), "1"); | assertEquals(wxMessage.getScanCodeInfo().getScanResult(), "1"); | ||||
assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1l)); | |||||
assertEquals(wxMessage.getSendPicsInfo().getCount(), new Long(1)); | |||||
assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "1b5f7c23b5bf75682a53e7b6d163e185"); | assertEquals(wxMessage.getSendPicsInfo().getPicList().get(0).getPicMd5Sum(), "1b5f7c23b5bf75682a53e7b6d163e185"); | ||||
assertEquals(wxMessage.getSendLocationInfo().getLocationX(), "23"); | assertEquals(wxMessage.getSendLocationInfo().getLocationX(), "23"); | ||||
assertEquals(wxMessage.getSendLocationInfo().getLocationY(), "113"); | assertEquals(wxMessage.getSendLocationInfo().getLocationY(), "113"); | ||||
@@ -9,7 +9,7 @@ public class WxCpXmlOutImageMessageTest { | |||||
public void test() { | public void test() { | ||||
WxCpXmlOutImageMessage m = new WxCpXmlOutImageMessage(); | WxCpXmlOutImageMessage m = new WxCpXmlOutImageMessage(); | ||||
m.setMediaId("ddfefesfsdfef"); | m.setMediaId("ddfefesfsdfef"); | ||||
m.setCreateTime(1122l); | |||||
m.setCreateTime(1122L); | |||||
m.setFromUserName("from"); | m.setFromUserName("from"); | ||||
m.setToUserName("to"); | m.setToUserName("to"); | ||||
@@ -8,7 +8,7 @@ public class WxCpXmlOutNewsMessageTest { | |||||
public void test() { | public void test() { | ||||
WxCpXmlOutNewsMessage m = new WxCpXmlOutNewsMessage(); | WxCpXmlOutNewsMessage m = new WxCpXmlOutNewsMessage(); | ||||
m.setCreateTime(1122l); | |||||
m.setCreateTime(1122L); | |||||
m.setFromUserName("fromUser"); | m.setFromUserName("fromUser"); | ||||
m.setToUserName("toUser"); | m.setToUserName("toUser"); | ||||
@@ -9,7 +9,7 @@ public class WxCpXmlOutTextMessageTest { | |||||
public void test() { | public void test() { | ||||
WxCpXmlOutTextMessage m = new WxCpXmlOutTextMessage(); | WxCpXmlOutTextMessage m = new WxCpXmlOutTextMessage(); | ||||
m.setContent("content"); | m.setContent("content"); | ||||
m.setCreateTime(1122l); | |||||
m.setCreateTime(1122L); | |||||
m.setFromUserName("from"); | m.setFromUserName("from"); | ||||
m.setToUserName("to"); | m.setToUserName("to"); | ||||
@@ -11,7 +11,7 @@ public class WxCpXmlOutVideoMessageTest { | |||||
m.setMediaId("media_id"); | m.setMediaId("media_id"); | ||||
m.setTitle("title"); | m.setTitle("title"); | ||||
m.setDescription("ddfff"); | m.setDescription("ddfff"); | ||||
m.setCreateTime(1122l); | |||||
m.setCreateTime(1122L); | |||||
m.setFromUserName("fromUser"); | m.setFromUserName("fromUser"); | ||||
m.setToUserName("toUser"); | m.setToUserName("toUser"); | ||||
@@ -9,7 +9,7 @@ public class WxCpXmlOutVoiceMessageTest { | |||||
public void test() { | public void test() { | ||||
WxCpXmlOutVoiceMessage m = new WxCpXmlOutVoiceMessage(); | WxCpXmlOutVoiceMessage m = new WxCpXmlOutVoiceMessage(); | ||||
m.setMediaId("ddfefesfsdfef"); | m.setMediaId("ddfefesfsdfef"); | ||||
m.setCreateTime(1122l); | |||||
m.setCreateTime(1122L); | |||||
m.setFromUserName("from"); | m.setFromUserName("from"); | ||||
m.setToUserName("to"); | m.setToUserName("to"); | ||||
@@ -7,10 +7,10 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>weixin-java-parent</artifactId> | <artifactId>weixin-java-parent</artifactId> | ||||
<version>2.9.0</version> | |||||
<version>2.9.9.BETA</version> | |||||
</parent> | </parent> | ||||
<artifactId>weixin-java-miniapp</artifactId> | <artifactId>weixin-java-miniapp</artifactId> | ||||
<name>WeiXin Java Tools - MiniApp</name> | |||||
<name>Weixin Java Tools - MiniApp</name> | |||||
<description>微信小程序Java SDK</description> | <description>微信小程序Java SDK</description> | ||||
<dependencies> | <dependencies> | ||||
@@ -61,10 +61,19 @@ | |||||
<artifactId>joda-time</artifactId> | <artifactId>joda-time</artifactId> | ||||
<scope>test</scope> | <scope>test</scope> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>org.assertj</groupId> | |||||
<artifactId>assertj-guava</artifactId> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>redis.clients</groupId> | <groupId>redis.clients</groupId> | ||||
<artifactId>jedis</artifactId> | <artifactId>jedis</artifactId> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>org.projectlombok</groupId> | |||||
<artifactId>lombok</artifactId> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
<build> | <build> | ||||
@@ -7,7 +7,7 @@ import java.io.File; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 二维码相关操作接口 | |||||
* 二维码相关操作接口. | |||||
* | * | ||||
* 接口A(createWxCode)加上接口C(createQrcode),总共生成的码数量限制为100,000,请谨慎调用。 | * 接口A(createWxCode)加上接口C(createQrcode),总共生成的码数量限制为100,000,请谨慎调用。 | ||||
* | * | ||||
@@ -22,9 +22,8 @@ public interface WxMaQrcodeService { | |||||
String GET_WXACODE_UNLIMIT_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit"; | String GET_WXACODE_UNLIMIT_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit"; | ||||
/** | /** | ||||
* 接口C | |||||
* 接口C: 获取小程序页面二维码. | |||||
* <pre> | * <pre> | ||||
* 获取小程序页面二维码 | |||||
* 适用于需要的码数量较少的业务场景 | * 适用于需要的码数量较少的业务场景 | ||||
* 通过该接口,仅能生成已发布的小程序的二维码。 | * 通过该接口,仅能生成已发布的小程序的二维码。 | ||||
* 可以在开发者工具预览时生成开发版的带参二维码。 | * 可以在开发者工具预览时生成开发版的带参二维码。 | ||||
@@ -39,8 +38,7 @@ public interface WxMaQrcodeService { | |||||
File createQrcode(String path) throws WxErrorException; | File createQrcode(String path) throws WxErrorException; | ||||
/** | /** | ||||
* 接口A | |||||
* 获取小程序码 | |||||
* 接口A: 获取小程序码. | |||||
* | * | ||||
* @param path 不能为空,最大长度 128 字节 | * @param path 不能为空,最大长度 128 字节 | ||||
* @param width 默认430 二维码的宽度 | * @param width 默认430 二维码的宽度 | ||||
@@ -54,14 +52,13 @@ public interface WxMaQrcodeService { | |||||
File createWxCode(String path) throws WxErrorException; | File createWxCode(String path) throws WxErrorException; | ||||
/** | /** | ||||
* 接口B | |||||
* 获取小程序码(永久有效、数量暂无限制) | |||||
* <p> | |||||
* 接口B: 获取小程序码(永久有效、数量暂无限制). | |||||
* <pre> | |||||
* 通过该接口生成的小程序码,永久有效,数量暂无限制。 | * 通过该接口生成的小程序码,永久有效,数量暂无限制。 | ||||
* 用户扫描该码进入小程序后,将统一打开首页,开发者需在对应页面根据获取的码中 scene 字段的值,再做处理逻辑。 | * 用户扫描该码进入小程序后,将统一打开首页,开发者需在对应页面根据获取的码中 scene 字段的值,再做处理逻辑。 | ||||
* 使用如下代码可以获取到二维码中的 scene 字段的值。 | * 使用如下代码可以获取到二维码中的 scene 字段的值。 | ||||
* 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode | * 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode | ||||
* | |||||
* </pre> | |||||
* @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) | * @param scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) | ||||
* @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面 | * @param page 必须是已经发布的小程序页面,例如 "pages/index/index" ,如果不填写这个字段,默认跳主页面 | ||||
* @param width 默认false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 | * @param width 默认false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 | ||||
@@ -1,5 +1,6 @@ | |||||
package cn.binarywang.wx.miniapp.api; | package cn.binarywang.wx.miniapp.api; | ||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; | |||||
import cn.binarywang.wx.miniapp.config.WxMaConfig; | import cn.binarywang.wx.miniapp.config.WxMaConfig; | ||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; | import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; | ||||
@@ -11,20 +12,27 @@ import me.chanjar.weixin.common.util.http.RequestHttp; | |||||
*/ | */ | ||||
public interface WxMaService { | public interface WxMaService { | ||||
/** | /** | ||||
* 获取access_token | |||||
* 获取access_token. | |||||
*/ | */ | ||||
String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; | String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; | ||||
String JSCODE_TO_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session"; | |||||
/** | |||||
* 获取登录后的session信息 | |||||
* | |||||
* @param jsCode 登录时获取的 code | |||||
*/ | |||||
WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 验证消息的确来自微信服务器 | |||||
* 验证消息的确来自微信服务器. | |||||
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN | * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN | ||||
* </pre> | * </pre> | ||||
*/ | */ | ||||
boolean checkSignature(String timestamp, String nonce, String signature); | boolean checkSignature(String timestamp, String nonce, String signature); | ||||
/** | /** | ||||
* 获取access_token, 不强制刷新access_token | |||||
* 获取access_token, 不强制刷新access_token. | |||||
* | * | ||||
* @see #getAccessToken(boolean) | * @see #getAccessToken(boolean) | ||||
*/ | */ | ||||
@@ -32,7 +40,7 @@ public interface WxMaService { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 获取access_token,本方法线程安全 | |||||
* 获取access_token,本方法线程安全. | |||||
* 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限 | * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限 | ||||
* | * | ||||
* 另:本service的所有方法都会在access_token过期是调用此方法 | * 另:本service的所有方法都会在access_token过期是调用此方法 | ||||
@@ -47,12 +55,12 @@ public interface WxMaService { | |||||
String getAccessToken(boolean forceRefresh) throws WxErrorException; | String getAccessToken(boolean forceRefresh) throws WxErrorException; | ||||
/** | /** | ||||
* 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 | |||||
* 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求. | |||||
*/ | */ | ||||
String get(String url, String queryParam) throws WxErrorException; | String get(String url, String queryParam) throws WxErrorException; | ||||
/** | /** | ||||
* 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 | |||||
* 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求. | |||||
*/ | */ | ||||
String post(String url, String postData) throws WxErrorException; | String post(String url, String postData) throws WxErrorException; | ||||
@@ -67,7 +75,7 @@ public interface WxMaService { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试 | |||||
* 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试. | |||||
* 默认:1000ms | * 默认:1000ms | ||||
* </pre> | * </pre> | ||||
*/ | */ | ||||
@@ -75,59 +83,65 @@ public interface WxMaService { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 设置当微信系统响应系统繁忙时,最大重试次数 | |||||
* 设置当微信系统响应系统繁忙时,最大重试次数. | |||||
* 默认:5次 | * 默认:5次 | ||||
* </pre> | * </pre> | ||||
*/ | */ | ||||
void setMaxRetryTimes(int maxRetryTimes); | void setMaxRetryTimes(int maxRetryTimes); | ||||
/** | /** | ||||
* 获取WxMaConfig 对象 | |||||
* 获取WxMaConfig 对象. | |||||
* | * | ||||
* @return WxMaConfig | * @return WxMaConfig | ||||
*/ | */ | ||||
WxMaConfig getWxMaConfig(); | WxMaConfig getWxMaConfig(); | ||||
/** | /** | ||||
* 注入 {@link WxMaConfig} 的实现 | |||||
* 注入 {@link WxMaConfig} 的实现. | |||||
*/ | */ | ||||
void setWxMaConfig(WxMaConfig wxConfigProvider); | void setWxMaConfig(WxMaConfig wxConfigProvider); | ||||
/** | /** | ||||
* 返回消息(客服消息和模版消息)发送接口方法实现类,以方便调用其各个接口 | |||||
* 返回消息(客服消息和模版消息)发送接口方法实现类,以方便调用其各个接口. | |||||
* | * | ||||
* @return WxMaMsgService | * @return WxMaMsgService | ||||
*/ | */ | ||||
WxMaMsgService getMsgService(); | WxMaMsgService getMsgService(); | ||||
/** | /** | ||||
* 返回素材相关接口方法的实现类对象,以方便调用其各个接口 | |||||
* 返回素材相关接口方法的实现类对象,以方便调用其各个接口. | |||||
* | * | ||||
* @return WxMaMediaService | * @return WxMaMediaService | ||||
*/ | */ | ||||
WxMaMediaService getMediaService(); | WxMaMediaService getMediaService(); | ||||
/** | /** | ||||
* 返回用户相关接口方法的实现类对象,以方便调用其各个接口 | |||||
* 返回用户相关接口方法的实现类对象,以方便调用其各个接口. | |||||
* | * | ||||
* @return WxMaUserService | * @return WxMaUserService | ||||
*/ | */ | ||||
WxMaUserService getUserService(); | WxMaUserService getUserService(); | ||||
/** | /** | ||||
* 返回二维码相关接口方法的实现类对象,以方便调用其各个接口 | |||||
* 返回二维码相关接口方法的实现类对象,以方便调用其各个接口. | |||||
* | * | ||||
* @return WxMaQrcodeService | * @return WxMaQrcodeService | ||||
*/ | */ | ||||
WxMaQrcodeService getQrcodeService(); | WxMaQrcodeService getQrcodeService(); | ||||
/** | /** | ||||
* 初始化http请求对象 | |||||
* 返回模板配置相关接口方法的实现类对象, 以方便调用其各个接口. | |||||
* @return WxMaTemplateService | |||||
*/ | |||||
WxMaTemplateService getTemplateService(); | |||||
/** | |||||
* 初始化http请求对象. | |||||
*/ | */ | ||||
void initHttp(); | void initHttp(); | ||||
/** | /** | ||||
* 请求http请求相关信息 | |||||
* 请求http请求相关信息. | |||||
*/ | */ | ||||
RequestHttp getRequestHttp(); | RequestHttp getRequestHttp(); | ||||
@@ -0,0 +1,89 @@ | |||||
package cn.binarywang.wx.miniapp.api; | |||||
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateAddResult; | |||||
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryGetResult; | |||||
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryListResult; | |||||
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateListResult; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import java.util.List; | |||||
public interface WxMaTemplateService { | |||||
//获取小程序模板库标题列表 | |||||
String TEMPLATE_LIBRARY_LIST_URL = "https://api.weixin.qq.com/cgi-bin/wxopen/template/library/list"; | |||||
//获取模板库某个模板标题下关键词库 | |||||
String TEMPLATE_LIBRARY_KEYWORD_URL = "https://api.weixin.qq.com/cgi-bin/wxopen/template/library/get"; | |||||
//组合模板并添加至帐号下的个人模板库 | |||||
String TEMPLATE_ADD_URL = "https://api.weixin.qq.com/cgi-bin/wxopen/template/add"; | |||||
//获取帐号下已存在的模板列表 | |||||
String TEMPLATE_LIST_URL = "https://api.weixin.qq.com/cgi-bin/wxopen/template/list"; | |||||
//删除帐号下的某个模板 | |||||
String TEMPLATE_DEL_URL = "https://api.weixin.qq.com/cgi-bin/wxopen/template/del"; | |||||
/** | |||||
* <pre> | |||||
* 获取小程序模板库标题列表 | |||||
* | |||||
* 详情请见: <a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1500465446_j4CgR&token=&lang=zh_CN">获取小程序模板库标题列表</a> | |||||
* 接口url格式: https://api.weixin.qq.com/cgi-bin/wxopen/template/library/list?access_token=ACCESS_TOKEN | |||||
* </pre> | |||||
* @param offset | |||||
* @param count | |||||
* @return | |||||
*/ | |||||
WxMaTemplateLibraryListResult findTemplateLibraryList(int offset, int count) throws WxErrorException; | |||||
/** | |||||
* <pre> | |||||
* 获取模板库某个模板标题下关键词库 | |||||
* | |||||
* 详情请见: <a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1500465446_j4CgR&token=&lang=zh_CN">获取小程序模板库标题列表</a> | |||||
* 接口url格式: https://api.weixin.qq.com/cgi-bin/wxopen/template/library/get?access_token=ACCESS_TOKEN | |||||
* </pre> | |||||
* @param id | |||||
* @return | |||||
*/ | |||||
WxMaTemplateLibraryGetResult findTemplateLibraryKeywordList(String id) throws WxErrorException; | |||||
/** | |||||
* <pre> | |||||
* 组合模板并添加至帐号下的个人模板库 | |||||
* | |||||
* 详情请见: <a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1500465446_j4CgR&token=&lang=zh_CN">获取小程序模板库标题列表</a> | |||||
* 接口url格式: https://api.weixin.qq.com/cgi-bin/wxopen/template/add?access_token=ACCESS_TOKEN | |||||
* </pre> | |||||
* @param id | |||||
* @param keywordIdList | |||||
* @return | |||||
*/ | |||||
WxMaTemplateAddResult addTemplate(String id, List<Integer> keywordIdList) throws WxErrorException; | |||||
/** | |||||
* <pre> | |||||
* 获取帐号下已存在的模板列表 | |||||
* | |||||
* 详情请见: <a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1500465446_j4CgR&token=&lang=zh_CN">获取小程序模板库标题列表</a> | |||||
* 接口url格式: https://api.weixin.qq.com/cgi-bin/wxopen/template/list?access_token=ACCESS_TOKEN | |||||
* </pre> | |||||
* @param offset | |||||
* @param count | |||||
* @return | |||||
*/ | |||||
WxMaTemplateListResult findTemplateList(int offset, int count) throws WxErrorException; | |||||
/** | |||||
* <pre> | |||||
* 删除帐号下的某个模板 | |||||
* | |||||
* 详情请见: <a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1500465446_j4CgR&token=&lang=zh_CN">获取小程序模板库标题列表</a> | |||||
* 接口url格式: https://api.weixin.qq.com/cgi-bin/wxopen/template/list?access_token=ACCESS_TOKEN | |||||
* </pre> | |||||
* @param templateId | |||||
*/ | |||||
boolean delTemplate(String templateId) throws WxErrorException; | |||||
} |
@@ -1,26 +1,26 @@ | |||||
package cn.binarywang.wx.miniapp.api; | package cn.binarywang.wx.miniapp.api; | ||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; | import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; | ||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; | import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; | ||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
/** | /** | ||||
* 用户信息相关操作接口 | |||||
* 用户信息相关操作接口. | |||||
* | * | ||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
*/ | */ | ||||
public interface WxMaUserService { | public interface WxMaUserService { | ||||
String JSCODE_TO_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session"; | |||||
/** | /** | ||||
* 获取登录后的session信息 | |||||
* 获取登录后的session信息. | |||||
* | * | ||||
* @param jsCode 登录时获取的 code | * @param jsCode 登录时获取的 code | ||||
*/ | */ | ||||
WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException; | WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException; | ||||
/** | /** | ||||
* 解密用户敏感数据 | |||||
* 解密用户敏感数据. | |||||
* | * | ||||
* @param sessionKey 会话密钥 | * @param sessionKey 会话密钥 | ||||
* @param encryptedData 消息密文 | * @param encryptedData 消息密文 | ||||
@@ -29,7 +29,16 @@ public interface WxMaUserService { | |||||
WxMaUserInfo getUserInfo(String sessionKey, String encryptedData, String ivStr); | WxMaUserInfo getUserInfo(String sessionKey, String encryptedData, String ivStr); | ||||
/** | /** | ||||
* 验证用户信息完整性 | |||||
* 解密用户手机号信息. | |||||
* | |||||
* @param sessionKey 会话密钥 | |||||
* @param encryptedData 消息密文 | |||||
* @param ivStr 加密算法的初始向量 | |||||
*/ | |||||
WxMaPhoneNumberInfo getPhoneNoInfo(String sessionKey, String encryptedData, String ivStr); | |||||
/** | |||||
* 验证用户信息完整性. | |||||
* | * | ||||
* @param sessionKey 会话密钥 | * @param sessionKey 会话密钥 | ||||
* @param rawData 微信用户基本信息 | * @param rawData 微信用户基本信息 | ||||
@@ -54,7 +54,8 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { | |||||
} | } | ||||
@Override | @Override | ||||
public File createWxCodeLimit(String scene, String page, int width, boolean autoColor, WxMaCodeLineColor lineColor) throws WxErrorException { | |||||
public File createWxCodeLimit(String scene, String page, int width, boolean autoColor, WxMaCodeLineColor lineColor) | |||||
throws WxErrorException { | |||||
WxMaWxcodeLimit wxMaWxcodeLimit = new WxMaWxcodeLimit(); | WxMaWxcodeLimit wxMaWxcodeLimit = new WxMaWxcodeLimit(); | ||||
wxMaWxcodeLimit.setScene(scene); | wxMaWxcodeLimit.setScene(scene); | ||||
wxMaWxcodeLimit.setPage(page); | wxMaWxcodeLimit.setPage(page); | ||||
@@ -1,16 +1,10 @@ | |||||
package cn.binarywang.wx.miniapp.api.impl; | package cn.binarywang.wx.miniapp.api.impl; | ||||
import cn.binarywang.wx.miniapp.api.*; | |||||
import cn.binarywang.wx.miniapp.config.WxMaConfig; | |||||
import cn.binarywang.wx.miniapp.constant.WxMaConstants; | |||||
import com.google.gson.JsonParser; | |||||
import me.chanjar.weixin.common.bean.WxAccessToken; | |||||
import me.chanjar.weixin.common.bean.result.WxError; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.common.util.crypto.SHA1; | |||||
import me.chanjar.weixin.common.util.http.*; | |||||
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; | |||||
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; | |||||
import java.io.IOException; | |||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
import java.util.concurrent.locks.Lock; | |||||
import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||
import org.apache.http.client.config.RequestConfig; | import org.apache.http.client.config.RequestConfig; | ||||
import org.apache.http.client.methods.CloseableHttpResponse; | import org.apache.http.client.methods.CloseableHttpResponse; | ||||
@@ -20,14 +14,32 @@ import org.apache.http.impl.client.CloseableHttpClient; | |||||
import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
import java.io.IOException; | |||||
import java.util.concurrent.locks.Lock; | |||||
import cn.binarywang.wx.miniapp.api.WxMaMediaService; | |||||
import cn.binarywang.wx.miniapp.api.WxMaMsgService; | |||||
import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; | |||||
import cn.binarywang.wx.miniapp.api.WxMaService; | |||||
import cn.binarywang.wx.miniapp.api.WxMaTemplateService; | |||||
import cn.binarywang.wx.miniapp.api.WxMaUserService; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; | |||||
import cn.binarywang.wx.miniapp.config.WxMaConfig; | |||||
import cn.binarywang.wx.miniapp.constant.WxMaConstants; | |||||
import com.google.common.base.Joiner; | |||||
import me.chanjar.weixin.common.bean.WxAccessToken; | |||||
import me.chanjar.weixin.common.bean.result.WxError; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.common.util.crypto.SHA1; | |||||
import me.chanjar.weixin.common.util.http.HttpType; | |||||
import me.chanjar.weixin.common.util.http.RequestExecutor; | |||||
import me.chanjar.weixin.common.util.http.RequestHttp; | |||||
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | |||||
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; | |||||
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; | |||||
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; | |||||
/** | /** | ||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
*/ | */ | ||||
public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpClient, HttpHost> { | public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpClient, HttpHost> { | ||||
private static final JsonParser JSON_PARSER = new JsonParser(); | |||||
private final Logger log = LoggerFactory.getLogger(this.getClass()); | private final Logger log = LoggerFactory.getLogger(this.getClass()); | ||||
private CloseableHttpClient httpClient; | private CloseableHttpClient httpClient; | ||||
@@ -38,6 +50,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
private WxMaMediaService materialService = new WxMaMediaServiceImpl(this); | private WxMaMediaService materialService = new WxMaMediaServiceImpl(this); | ||||
private WxMaUserService userService = new WxMaUserServiceImpl(this); | private WxMaUserService userService = new WxMaUserServiceImpl(this); | ||||
private WxMaQrcodeService qrCodeService = new WxMaQrcodeServiceImpl(this); | private WxMaQrcodeService qrCodeService = new WxMaQrcodeServiceImpl(this); | ||||
private WxMaTemplateService templateService = new WxMaTemplateServiceImpl(this); | |||||
private int retrySleepMillis = 1000; | private int retrySleepMillis = 1000; | ||||
private int maxRetryTimes = 5; | private int maxRetryTimes = 5; | ||||
@@ -120,6 +133,19 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
return this.getWxMaConfig().getAccessToken(); | return this.getWxMaConfig().getAccessToken(); | ||||
} | } | ||||
@Override | |||||
public WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException { | |||||
final WxMaConfig config = getWxMaConfig(); | |||||
Map<String, String> params = new HashMap<>(8); | |||||
params.put("appid", config.getAppid()); | |||||
params.put("secret", config.getSecret()); | |||||
params.put("js_code", jsCode); | |||||
params.put("grant_type", "authorization_code"); | |||||
String result = get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params)); | |||||
return WxMaJscode2SessionResult.fromJson(result); | |||||
} | |||||
@Override | @Override | ||||
public boolean checkSignature(String timestamp, String nonce, String signature) { | public boolean checkSignature(String timestamp, String nonce, String signature) { | ||||
try { | try { | ||||
@@ -259,4 +285,9 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||||
public WxMaQrcodeService getQrcodeService() { | public WxMaQrcodeService getQrcodeService() { | ||||
return this.qrCodeService; | return this.qrCodeService; | ||||
} | } | ||||
@Override | |||||
public WxMaTemplateService getTemplateService() { | |||||
return this.templateService; | |||||
} | |||||
} | } |
@@ -0,0 +1,101 @@ | |||||
package cn.binarywang.wx.miniapp.api.impl; | |||||
import cn.binarywang.wx.miniapp.api.WxMaService; | |||||
import cn.binarywang.wx.miniapp.api.WxMaTemplateService; | |||||
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateAddResult; | |||||
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryGetResult; | |||||
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryListResult; | |||||
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateListResult; | |||||
import me.chanjar.weixin.common.bean.result.WxError; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
import java.util.HashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
public class WxMaTemplateServiceImpl implements WxMaTemplateService { | |||||
private WxMaService wxMaService; | |||||
public WxMaTemplateServiceImpl(WxMaService wxMaService){ | |||||
this.wxMaService = wxMaService; | |||||
} | |||||
@Override | |||||
public WxMaTemplateLibraryListResult findTemplateLibraryList(int offset, int count) throws WxErrorException { | |||||
Map<String, Integer> params = new HashMap<>(); | |||||
params.put("offset", offset); | |||||
params.put("count", count); | |||||
String responseText = this.wxMaService.post(TEMPLATE_LIBRARY_LIST_URL, WxGsonBuilder.create().toJson(params)); | |||||
WxError wxError = WxError.fromJson(responseText); | |||||
if(wxError.getErrorCode() == 0){ | |||||
return WxMaTemplateLibraryListResult.fromJson(responseText); | |||||
}else { | |||||
throw new WxErrorException(wxError); | |||||
} | |||||
} | |||||
@Override | |||||
public WxMaTemplateLibraryGetResult findTemplateLibraryKeywordList(String id) throws WxErrorException { | |||||
Map<String, String> params = new HashMap<>(); | |||||
params.put("id", id); | |||||
String responseText = this.wxMaService.post(TEMPLATE_LIBRARY_KEYWORD_URL, WxGsonBuilder.create().toJson(params)); | |||||
WxError wxError = WxError.fromJson(responseText); | |||||
if(wxError.getErrorCode() == 0){ | |||||
return WxMaTemplateLibraryGetResult.fromJson(responseText); | |||||
}else { | |||||
throw new WxErrorException(wxError); | |||||
} | |||||
} | |||||
@Override | |||||
public WxMaTemplateAddResult addTemplate(String id, List<Integer> keywordIdList) throws WxErrorException { | |||||
Map<String, Object> params = new HashMap<>(); | |||||
params.put("id", id); | |||||
params.put("keyword_id_list", keywordIdList.toArray()); | |||||
String responseText = this.wxMaService.post(TEMPLATE_ADD_URL, WxGsonBuilder.create().toJson(params)); | |||||
WxError wxError = WxError.fromJson(responseText); | |||||
if(wxError.getErrorCode() == 0){ | |||||
return WxMaTemplateAddResult.fromJson(responseText); | |||||
}else { | |||||
throw new WxErrorException(wxError); | |||||
} | |||||
} | |||||
@Override | |||||
public WxMaTemplateListResult findTemplateList(int offset, int count) throws WxErrorException { | |||||
Map<String, Integer> params = new HashMap<>(); | |||||
params.put("offset", offset); | |||||
params.put("count", count); | |||||
String responseText = this.wxMaService.post(TEMPLATE_LIST_URL, WxGsonBuilder.create().toJson(params)); | |||||
WxError wxError = WxError.fromJson(responseText); | |||||
if(wxError.getErrorCode() == 0){ | |||||
return WxMaTemplateListResult.fromJson(responseText); | |||||
}else { | |||||
throw new WxErrorException(wxError); | |||||
} | |||||
} | |||||
@Override | |||||
public boolean delTemplate(String templateId) throws WxErrorException { | |||||
Map<String, String> params = new HashMap<>(); | |||||
params.put("template_id", templateId); | |||||
String responseText = this.wxMaService.post(TEMPLATE_DEL_URL, WxGsonBuilder.create().toJson(params)); | |||||
WxError wxError = WxError.fromJson(responseText); | |||||
if(wxError.getErrorCode() == 0){ | |||||
return true; | |||||
}else { | |||||
throw new WxErrorException(wxError); | |||||
} | |||||
} | |||||
} |
@@ -1,17 +1,14 @@ | |||||
package cn.binarywang.wx.miniapp.api.impl; | package cn.binarywang.wx.miniapp.api.impl; | ||||
import org.apache.commons.codec.digest.DigestUtils; | |||||
import cn.binarywang.wx.miniapp.api.WxMaService; | import cn.binarywang.wx.miniapp.api.WxMaService; | ||||
import cn.binarywang.wx.miniapp.api.WxMaUserService; | import cn.binarywang.wx.miniapp.api.WxMaUserService; | ||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; | import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; | ||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; | import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; | ||||
import cn.binarywang.wx.miniapp.config.WxMaConfig; | |||||
import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; | import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; | ||||
import com.google.common.base.Joiner; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
import org.apache.commons.codec.digest.DigestUtils; | |||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
/** | /** | ||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
@@ -25,15 +22,7 @@ public class WxMaUserServiceImpl implements WxMaUserService { | |||||
@Override | @Override | ||||
public WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException { | public WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException { | ||||
final WxMaConfig config = service.getWxMaConfig(); | |||||
Map<String, String> params = new HashMap<>(8); | |||||
params.put("appid", config.getAppid()); | |||||
params.put("secret", config.getSecret()); | |||||
params.put("js_code", jsCode); | |||||
params.put("grant_type", "authorization_code"); | |||||
String result = this.service.get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params)); | |||||
return WxMaJscode2SessionResult.fromJson(result); | |||||
return service.jsCode2SessionInfo(jsCode); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -41,10 +30,14 @@ public class WxMaUserServiceImpl implements WxMaUserService { | |||||
return WxMaUserInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr)); | return WxMaUserInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr)); | ||||
} | } | ||||
@Override | |||||
public WxMaPhoneNumberInfo getPhoneNoInfo(String sessionKey, String encryptedData, String ivStr) { | |||||
return WxMaPhoneNumberInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr)); | |||||
} | |||||
@Override | @Override | ||||
public boolean checkUserInfo(String sessionKey, String rawData, String signature) { | public boolean checkUserInfo(String sessionKey, String rawData, String signature) { | ||||
final String generatedSignature = DigestUtils.sha1Hex(rawData + sessionKey); | final String generatedSignature = DigestUtils.sha1Hex(rawData + sessionKey); | ||||
System.out.println(generatedSignature); | |||||
return generatedSignature.equals(signature); | return generatedSignature.equals(signature); | ||||
} | } | ||||
@@ -8,10 +8,12 @@ import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||||
* @author Element | * @author Element | ||||
*/ | */ | ||||
public abstract class AbstractWxMaQrcodeWrapper { | public abstract class AbstractWxMaQrcodeWrapper { | ||||
public String toJson() { | |||||
return WxMaGsonBuilder.create().toJson(this); | |||||
} | |||||
@Override | @Override | ||||
public String toString() { | public String toString() { | ||||
return WxMaGsonBuilder.create().toJson(this); | |||||
return this.toJson(); | |||||
} | } | ||||
} | } |
@@ -8,8 +8,11 @@ import lombok.EqualsAndHashCode; | |||||
import java.io.Serializable; | import java.io.Serializable; | ||||
/** | /** | ||||
* {"session_key":"nzoqhc3OnwHzeTxJs+inbQ==","expires_in":2592000,"openid":"oVBkZ0aYgDMDIywRdgPW8-joxXc4"} | |||||
* | |||||
* <pre> | |||||
* code换取session_key接口的响应 | |||||
* 文档地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html#wxloginobject | |||||
* 微信返回报文:{"session_key":"nzoqhc3OnwHzeTxJs+inbQ==","openid":"oVBkZ0aYgDMDIywRdgPW8-joxXc4"} | |||||
* </pre> | |||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
*/ | */ | ||||
@Data | @Data | ||||
@@ -20,9 +23,6 @@ public class WxMaJscode2SessionResult implements Serializable { | |||||
@SerializedName("session_key") | @SerializedName("session_key") | ||||
private String sessionKey; | private String sessionKey; | ||||
@SerializedName("expires_in") | |||||
private Integer expiresin; | |||||
@SerializedName("openid") | @SerializedName("openid") | ||||
private String openid; | private String openid; | ||||
@@ -1,14 +1,19 @@ | |||||
package cn.binarywang.wx.miniapp.bean; | package cn.binarywang.wx.miniapp.bean; | ||||
import cn.binarywang.wx.miniapp.builder.ImageBuilder; | |||||
import cn.binarywang.wx.miniapp.builder.TextBuilder; | |||||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||||
import cn.binarywang.wx.miniapp.builder.ImageMessageBuilder; | |||||
import cn.binarywang.wx.miniapp.builder.LinkMessageBuilder; | |||||
import cn.binarywang.wx.miniapp.builder.MaPageMessageBuilder; | |||||
import cn.binarywang.wx.miniapp.builder.TextMessageBuilder; | |||||
import com.google.gson.GsonBuilder; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Builder; | |||||
import lombok.Data; | import lombok.Data; | ||||
import java.io.Serializable; | import java.io.Serializable; | ||||
/** | /** | ||||
* 客服消息 | |||||
* 客服消息. | |||||
* | * | ||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
*/ | */ | ||||
@@ -16,30 +21,90 @@ import java.io.Serializable; | |||||
public class WxMaKefuMessage implements Serializable { | public class WxMaKefuMessage implements Serializable { | ||||
private static final long serialVersionUID = -9196732086954365246L; | private static final long serialVersionUID = -9196732086954365246L; | ||||
@SerializedName("touser") | |||||
private String toUser; | private String toUser; | ||||
@SerializedName("msgtype") | |||||
private String msgType; | private String msgType; | ||||
private String content; | |||||
private String mediaId; | |||||
private String thumbMediaId; | |||||
private String title; | |||||
private String description; | |||||
@SerializedName("text") | |||||
private KfText text; | |||||
@SerializedName("image") | |||||
private KfImage image; | |||||
@SerializedName("link") | |||||
private KfLink link; | |||||
@SerializedName("miniprogrampage") | |||||
private KfMaPage maPage; | |||||
@Data | |||||
@AllArgsConstructor | |||||
public static class KfText { | |||||
private String content; | |||||
} | |||||
@Data | |||||
@AllArgsConstructor | |||||
public static class KfImage { | |||||
@SerializedName("media_id") | |||||
private String mediaId; | |||||
} | |||||
@Data | |||||
@Builder | |||||
public static class KfLink { | |||||
private String title; | |||||
private String description; | |||||
private String url; | |||||
@SerializedName("thumb_url") | |||||
private String thumbUrl; | |||||
} | |||||
@Data | |||||
@Builder | |||||
public static class KfMaPage { | |||||
private String title; | |||||
@SerializedName("pagepath") | |||||
private String pagePath; | |||||
@SerializedName("thumb_media_id") | |||||
private String thumbMediaId; | |||||
} | |||||
/** | |||||
* 获得文本消息builder. | |||||
*/ | |||||
public static TextMessageBuilder newTextBuilder() { | |||||
return new TextMessageBuilder(); | |||||
} | |||||
/** | |||||
* 获得图片消息builder. | |||||
*/ | |||||
public static ImageMessageBuilder newImageBuilder() { | |||||
return new ImageMessageBuilder(); | |||||
} | |||||
/** | /** | ||||
* 获得文本消息builder | |||||
* 获得图文链接消息builder. | |||||
*/ | */ | ||||
public static TextBuilder newTextBuilder() { | |||||
return new TextBuilder(); | |||||
public static LinkMessageBuilder newLinkBuilder() { | |||||
return new LinkMessageBuilder(); | |||||
} | } | ||||
/** | /** | ||||
* 获得图片消息builder | |||||
* 获得图文链接消息builder. | |||||
*/ | */ | ||||
public static ImageBuilder newImageBuilder() { | |||||
return new ImageBuilder(); | |||||
public static MaPageMessageBuilder newMaPageBuilder() { | |||||
return new MaPageMessageBuilder(); | |||||
} | } | ||||
public String toJson() { | public String toJson() { | ||||
return WxMaGsonBuilder.create().toJson(this); | |||||
return new GsonBuilder().create().toJson(this); | |||||
} | } | ||||
} | } |
@@ -45,12 +45,16 @@ public class WxMaMessage implements Serializable { | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | @XStreamConverter(value = XStreamCDataConverter.class) | ||||
private Integer createTime; | private Integer createTime; | ||||
@SerializedName("MsgType") | |||||
@XStreamAlias("MsgType") | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String msgType; | |||||
@SerializedName("MsgDataFormat") | @SerializedName("MsgDataFormat") | ||||
@XStreamAlias("MsgDataFormat") | @XStreamAlias("MsgDataFormat") | ||||
@XStreamConverter(value = XStreamCDataConverter.class) | @XStreamConverter(value = XStreamCDataConverter.class) | ||||
private String msgType; | |||||
private String msgDataFormat; | |||||
// 文本消息 | |||||
@SerializedName("Content") | @SerializedName("Content") | ||||
@XStreamAlias("Content") | @XStreamAlias("Content") | ||||
@XStreamConverter(value = XStreamCDataConverter.class) | @XStreamConverter(value = XStreamCDataConverter.class) | ||||
@@ -61,7 +65,6 @@ public class WxMaMessage implements Serializable { | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | @XStreamConverter(value = XStreamCDataConverter.class) | ||||
private Long msgId; | private Long msgId; | ||||
// 图片消息 | |||||
@SerializedName("PicUrl") | @SerializedName("PicUrl") | ||||
@XStreamAlias("PicUrl") | @XStreamAlias("PicUrl") | ||||
@XStreamConverter(value = XStreamCDataConverter.class) | @XStreamConverter(value = XStreamCDataConverter.class) | ||||
@@ -72,7 +75,6 @@ public class WxMaMessage implements Serializable { | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | @XStreamConverter(value = XStreamCDataConverter.class) | ||||
private String mediaId; | private String mediaId; | ||||
// 事件消息 | |||||
@SerializedName("Event") | @SerializedName("Event") | ||||
@XStreamAlias("Event") | @XStreamAlias("Event") | ||||
@XStreamConverter(value = XStreamCDataConverter.class) | @XStreamConverter(value = XStreamCDataConverter.class) | ||||
@@ -92,7 +94,7 @@ public class WxMaMessage implements Serializable { | |||||
} | } | ||||
/** | /** | ||||
* 从加密字符串转换 | |||||
* 从加密字符串转换. | |||||
* | * | ||||
* @param encryptedXml 密文 | * @param encryptedXml 密文 | ||||
* @param wxMaConfig 配置存储器对象 | * @param wxMaConfig 配置存储器对象 | ||||
@@ -0,0 +1,30 @@ | |||||
package cn.binarywang.wx.miniapp.bean; | |||||
import java.io.Serializable; | |||||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||||
import lombok.Data; | |||||
/** | |||||
* 微信用户绑定的手机号相关信息 | |||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
*/ | |||||
@Data | |||||
public class WxMaPhoneNumberInfo implements Serializable { | |||||
private static final long serialVersionUID = 6719822331555402137L; | |||||
private String phoneNumber; | |||||
private String purePhoneNumber; | |||||
private String countryCode; | |||||
private Watermark watermark; | |||||
public static WxMaPhoneNumberInfo fromJson(String json) { | |||||
return WxMaGsonBuilder.create().fromJson(json, WxMaPhoneNumberInfo.class); | |||||
} | |||||
@Data | |||||
public static class Watermark { | |||||
private String timestamp; | |||||
private String appid; | |||||
} | |||||
} |
@@ -1,24 +1,28 @@ | |||||
package cn.binarywang.wx.miniapp.bean; | package cn.binarywang.wx.miniapp.bean; | ||||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | ||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.*; | |||||
import java.io.Serializable; | import java.io.Serializable; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
/** | /** | ||||
* 模板消息. | |||||
* 参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/notice.html#接口说明 模板消息部分 | * 参考 https://mp.weixin.qq.com/debug/wxadoc/dev/api/notice.html#接口说明 模板消息部分 | ||||
* | * | ||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
*/ | */ | ||||
@Data | |||||
@Getter | |||||
@Setter | |||||
@NoArgsConstructor | |||||
@AllArgsConstructor | |||||
@Builder | @Builder | ||||
public class WxMaTemplateMessage implements Serializable { | public class WxMaTemplateMessage implements Serializable { | ||||
private static final long serialVersionUID = 5063374783759519418L; | private static final long serialVersionUID = 5063374783759519418L; | ||||
/** | /** | ||||
* 接收者(用户)的 openid. | |||||
* <pre> | * <pre> | ||||
* 参数:touser | * 参数:touser | ||||
* 是否必填: 是 | * 是否必填: 是 | ||||
@@ -28,6 +32,7 @@ public class WxMaTemplateMessage implements Serializable { | |||||
private String toUser; | private String toUser; | ||||
/** | /** | ||||
* 所需下发的模板消息的id. | |||||
* <pre> | * <pre> | ||||
* 参数:template_id | * 参数:template_id | ||||
* 是否必填: 是 | * 是否必填: 是 | ||||
@@ -37,6 +42,7 @@ public class WxMaTemplateMessage implements Serializable { | |||||
private String templateId; | private String templateId; | ||||
/** | /** | ||||
* 点击模板卡片后的跳转页面,仅限本小程序内的页面. | |||||
* <pre> | * <pre> | ||||
* 参数:page | * 参数:page | ||||
* 是否必填: 否 | * 是否必填: 否 | ||||
@@ -46,6 +52,7 @@ public class WxMaTemplateMessage implements Serializable { | |||||
private String page; | private String page; | ||||
/** | /** | ||||
* 表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id. | |||||
* <pre> | * <pre> | ||||
* 参数:form_id | * 参数:form_id | ||||
* 是否必填: 是 | * 是否必填: 是 | ||||
@@ -55,16 +62,17 @@ public class WxMaTemplateMessage implements Serializable { | |||||
private String formId; | private String formId; | ||||
/** | /** | ||||
* 模板内容,不填则下发空模板. | |||||
* <pre> | * <pre> | ||||
* 参数:data | * 参数:data | ||||
* 是否必填: 是 | * 是否必填: 是 | ||||
* 描述: 模板内容,不填则下发空模板 | * 描述: 模板内容,不填则下发空模板 | ||||
* </pre> | * </pre> | ||||
*/ | */ | ||||
@Builder.Default | |||||
private final List<Data> data = new ArrayList<>(); | |||||
private List<Data> data; | |||||
/** | /** | ||||
* 模板内容字体的颜色,不填默认黑色. | |||||
* <pre> | * <pre> | ||||
* 参数:color | * 参数:color | ||||
* 是否必填: 否 | * 是否必填: 否 | ||||
@@ -74,6 +82,7 @@ public class WxMaTemplateMessage implements Serializable { | |||||
private String color; | private String color; | ||||
/** | /** | ||||
* 模板需要放大的关键词,不填则默认无放大. | |||||
* <pre> | * <pre> | ||||
* 参数:emphasis_keyword | * 参数:emphasis_keyword | ||||
* 是否必填: 否 | * 是否必填: 否 | ||||
@@ -82,6 +91,15 @@ public class WxMaTemplateMessage implements Serializable { | |||||
*/ | */ | ||||
private String emphasisKeyword; | private String emphasisKeyword; | ||||
public WxMaTemplateMessage addData(Data datum) { | |||||
if (this.data == null) { | |||||
this.data = new ArrayList<>(); | |||||
} | |||||
this.data.add(datum); | |||||
return this; | |||||
} | |||||
public String toJson() { | public String toJson() { | ||||
return WxMaGsonBuilder.create().toJson(this); | return WxMaGsonBuilder.create().toJson(this); | ||||
} | } | ||||
@@ -8,6 +8,7 @@ import lombok.EqualsAndHashCode; | |||||
import java.io.Serializable; | import java.io.Serializable; | ||||
/** | /** | ||||
* 小程序码接口B. | |||||
* | * | ||||
* @author Element | * @author Element | ||||
* @date 2017/7/27 | * @date 2017/7/27 | ||||
@@ -0,0 +1,20 @@ | |||||
package cn.binarywang.wx.miniapp.bean.template; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
import java.io.Serializable; | |||||
@Data | |||||
public class WxMaTemplateAddResult implements Serializable{ | |||||
private static final long serialVersionUID = 872250961973834465L; | |||||
@SerializedName("template_id") | |||||
private String templateId; | |||||
public static WxMaTemplateAddResult fromJson(String json){ | |||||
return WxGsonBuilder.create().fromJson(json, WxMaTemplateAddResult.class); | |||||
} | |||||
} |
@@ -0,0 +1,31 @@ | |||||
package cn.binarywang.wx.miniapp.bean.template; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
@Data | |||||
public class WxMaTemplateLibraryGetResult implements Serializable{ | |||||
private static final long serialVersionUID = -190847592776636744L; | |||||
private String id; | |||||
private String title; | |||||
@SerializedName("keyword_list") | |||||
private List<KeywordInfo> keywordList; | |||||
@Data | |||||
public static class KeywordInfo{ | |||||
@SerializedName("keyword_id") | |||||
private int keywordId; | |||||
private String name; | |||||
private String example; | |||||
} | |||||
public static WxMaTemplateLibraryGetResult fromJson(String json){ | |||||
return WxGsonBuilder.create().fromJson(json, WxMaTemplateLibraryGetResult.class); | |||||
} | |||||
} |
@@ -0,0 +1,28 @@ | |||||
package cn.binarywang.wx.miniapp.bean.template; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
@Data | |||||
public class WxMaTemplateLibraryListResult implements Serializable{ | |||||
private static final long serialVersionUID = -2780782521447602209L; | |||||
@SerializedName("total_count") | |||||
private int totalCount; | |||||
private List<TemplateItem> list; | |||||
public static WxMaTemplateLibraryListResult fromJson(String json){ | |||||
return WxGsonBuilder.create().fromJson(json, WxMaTemplateLibraryListResult.class); | |||||
} | |||||
@Data | |||||
public static class TemplateItem{ | |||||
private String id; | |||||
private String title; | |||||
} | |||||
} |
@@ -0,0 +1,29 @@ | |||||
package cn.binarywang.wx.miniapp.bean.template; | |||||
import com.google.gson.annotations.SerializedName; | |||||
import lombok.Data; | |||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
@Data | |||||
public class WxMaTemplateListResult implements Serializable{ | |||||
private static final long serialVersionUID = -7430535579782184537L; | |||||
private List<TemplateInfo> list; | |||||
public static WxMaTemplateListResult fromJson(String json){ | |||||
return WxGsonBuilder.create().fromJson(json, WxMaTemplateListResult.class); | |||||
} | |||||
@Data | |||||
public static class TemplateInfo{ | |||||
@SerializedName("template_id") | |||||
private String templateId; | |||||
private String title; | |||||
private String content; | |||||
private String example; | |||||
} | |||||
} |
@@ -1,27 +0,0 @@ | |||||
package cn.binarywang.wx.miniapp.builder; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||||
import cn.binarywang.wx.miniapp.constant.WxMaConstants; | |||||
/** | |||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
*/ | |||||
public final class ImageBuilder extends BaseBuilder<ImageBuilder> { | |||||
private String mediaId; | |||||
public ImageBuilder() { | |||||
this.msgType = WxMaConstants.KefuMsgType.IMAGE; | |||||
} | |||||
public ImageBuilder mediaId(String mediaId) { | |||||
this.mediaId = mediaId; | |||||
return this; | |||||
} | |||||
@Override | |||||
public WxMaKefuMessage build() { | |||||
WxMaKefuMessage m = super.build(); | |||||
m.setMediaId(this.mediaId); | |||||
return m; | |||||
} | |||||
} |
@@ -0,0 +1,30 @@ | |||||
package cn.binarywang.wx.miniapp.builder; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||||
import static cn.binarywang.wx.miniapp.constant.WxMaConstants.KefuMsgType; | |||||
/** | |||||
* 图片消息builder. | |||||
* | |||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
*/ | |||||
public final class ImageMessageBuilder extends BaseBuilder<ImageMessageBuilder> { | |||||
private String mediaId; | |||||
public ImageMessageBuilder() { | |||||
this.msgType = KefuMsgType.IMAGE; | |||||
} | |||||
public ImageMessageBuilder mediaId(String mediaId) { | |||||
this.mediaId = mediaId; | |||||
return this; | |||||
} | |||||
@Override | |||||
public WxMaKefuMessage build() { | |||||
WxMaKefuMessage m = super.build(); | |||||
m.setImage(new WxMaKefuMessage.KfImage(this.mediaId)); | |||||
return m; | |||||
} | |||||
} |
@@ -0,0 +1,53 @@ | |||||
package cn.binarywang.wx.miniapp.builder; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||||
import static cn.binarywang.wx.miniapp.constant.WxMaConstants.KefuMsgType; | |||||
/** | |||||
* 图文链接消息builder | |||||
* | |||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
*/ | |||||
public class LinkMessageBuilder extends BaseBuilder<LinkMessageBuilder> { | |||||
private String title; | |||||
private String description; | |||||
private String url; | |||||
private String thumbUrl; | |||||
public LinkMessageBuilder() { | |||||
this.msgType = KefuMsgType.LINK; | |||||
} | |||||
public LinkMessageBuilder title(String title) { | |||||
this.title = title; | |||||
return this; | |||||
} | |||||
public LinkMessageBuilder description(String description) { | |||||
this.description = description; | |||||
return this; | |||||
} | |||||
public LinkMessageBuilder url(String url) { | |||||
this.url = url; | |||||
return this; | |||||
} | |||||
public LinkMessageBuilder thumbUrl(String thumbUrl) { | |||||
this.thumbUrl = thumbUrl; | |||||
return this; | |||||
} | |||||
@Override | |||||
public WxMaKefuMessage build() { | |||||
WxMaKefuMessage m = super.build(); | |||||
m.setLink(WxMaKefuMessage.KfLink.builder().title(this.title) | |||||
.description(this.description) | |||||
.url(this.url) | |||||
.thumbUrl(this.thumbUrl) | |||||
.build() | |||||
); | |||||
return m; | |||||
} | |||||
} |
@@ -0,0 +1,47 @@ | |||||
package cn.binarywang.wx.miniapp.builder; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||||
import static cn.binarywang.wx.miniapp.constant.WxMaConstants.KefuMsgType; | |||||
/** | |||||
* 小程序卡片消息builder | |||||
* | |||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
*/ | |||||
public class MaPageMessageBuilder extends BaseBuilder<MaPageMessageBuilder> { | |||||
private String title; | |||||
private String pagePath; | |||||
private String thumbMediaId; | |||||
public MaPageMessageBuilder() { | |||||
this.msgType = KefuMsgType.MA_PAGE; | |||||
} | |||||
public MaPageMessageBuilder title(String title) { | |||||
this.title = title; | |||||
return this; | |||||
} | |||||
public MaPageMessageBuilder pagePath(String pagePath) { | |||||
this.pagePath = pagePath; | |||||
return this; | |||||
} | |||||
public MaPageMessageBuilder thumbMediaId(String thumbMediaId) { | |||||
this.thumbMediaId = thumbMediaId; | |||||
return this; | |||||
} | |||||
@Override | |||||
public WxMaKefuMessage build() { | |||||
WxMaKefuMessage m = super.build(); | |||||
m.setMaPage(WxMaKefuMessage.KfMaPage.builder() | |||||
.title(this.title) | |||||
.pagePath(this.pagePath) | |||||
.thumbMediaId(this.thumbMediaId) | |||||
.build() | |||||
); | |||||
return m; | |||||
} | |||||
} |
@@ -1,27 +0,0 @@ | |||||
package cn.binarywang.wx.miniapp.builder; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||||
import cn.binarywang.wx.miniapp.constant.WxMaConstants; | |||||
/** | |||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
*/ | |||||
public final class TextBuilder extends BaseBuilder<TextBuilder> { | |||||
private String content; | |||||
public TextBuilder() { | |||||
this.msgType = WxMaConstants.KefuMsgType.TEXT; | |||||
} | |||||
public TextBuilder content(String content) { | |||||
this.content = content; | |||||
return this; | |||||
} | |||||
@Override | |||||
public WxMaKefuMessage build() { | |||||
WxMaKefuMessage m = super.build(); | |||||
m.setContent(this.content); | |||||
return m; | |||||
} | |||||
} |
@@ -0,0 +1,30 @@ | |||||
package cn.binarywang.wx.miniapp.builder; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||||
import static cn.binarywang.wx.miniapp.constant.WxMaConstants.KefuMsgType; | |||||
/** | |||||
* 文本消息builder. | |||||
* | |||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
*/ | |||||
public final class TextMessageBuilder extends BaseBuilder<TextMessageBuilder> { | |||||
private String content; | |||||
public TextMessageBuilder() { | |||||
this.msgType = KefuMsgType.TEXT; | |||||
} | |||||
public TextMessageBuilder content(String content) { | |||||
this.content = content; | |||||
return this; | |||||
} | |||||
@Override | |||||
public WxMaKefuMessage build() { | |||||
WxMaKefuMessage m = super.build(); | |||||
m.setText(new WxMaKefuMessage.KfText(this.content)); | |||||
return m; | |||||
} | |||||
} |
@@ -2,29 +2,29 @@ package cn.binarywang.wx.miniapp.constant; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 小程序常量 | |||||
* 小程序常量. | |||||
* </pre> | * </pre> | ||||
* | * | ||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
*/ | */ | ||||
public class WxMaConstants { | public class WxMaConstants { | ||||
/** | /** | ||||
* 微信接口返回的参数errcode | |||||
* 微信接口返回的参数errcode. | |||||
*/ | */ | ||||
public static final String ERRCODE = "errcode"; | public static final String ERRCODE = "errcode"; | ||||
/** | /** | ||||
* 素材类型 | |||||
* 素材类型. | |||||
*/ | */ | ||||
public static class MediaType { | public static class MediaType { | ||||
/** | /** | ||||
* 图片 | |||||
* 图片. | |||||
*/ | */ | ||||
public static final String IMAGE = "image"; | public static final String IMAGE = "image"; | ||||
} | } | ||||
/** | /** | ||||
* 消息格式 | |||||
* 消息格式. | |||||
*/ | */ | ||||
public static class MsgDataFormat { | public static class MsgDataFormat { | ||||
public static final String XML = "XML"; | public static final String XML = "XML"; | ||||
@@ -32,32 +32,40 @@ public class WxMaConstants { | |||||
} | } | ||||
/** | /** | ||||
* 客服消息的消息类型 | |||||
* 客服消息的消息类型. | |||||
*/ | */ | ||||
public static class KefuMsgType { | public static class KefuMsgType { | ||||
/** | /** | ||||
* 文本消息 | |||||
* 文本消息. | |||||
*/ | */ | ||||
public static final String TEXT = "text"; | public static final String TEXT = "text"; | ||||
/** | /** | ||||
* 图片消息 | |||||
* 图片消息. | |||||
*/ | */ | ||||
public static final String IMAGE = "image"; | public static final String IMAGE = "image"; | ||||
/** | |||||
* 图文链接. | |||||
*/ | |||||
public static final String LINK = "link"; | |||||
/** | |||||
* 小程序卡片消息. | |||||
*/ | |||||
public static final String MA_PAGE = "miniprogrampage"; | |||||
} | } | ||||
public static final class ErrorCode { | public static final class ErrorCode { | ||||
/** | /** | ||||
* 40001 获取access_token时AppSecret错误,或者access_token无效 | |||||
* 40001 获取access_token时AppSecret错误,或者access_token无效. | |||||
*/ | */ | ||||
public static final int ERR_40001 = 40001; | public static final int ERR_40001 = 40001; | ||||
/** | /** | ||||
* 42001 access_token超时 | |||||
* 42001 access_token超时. | |||||
*/ | */ | ||||
public static final int ERR_42001 = 42001; | public static final int ERR_42001 = 42001; | ||||
/** | /** | ||||
* 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期) | |||||
* 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期). | |||||
*/ | */ | ||||
public static final int ERR_40014 = 40014; | public static final int ERR_40014 = 40014; | ||||
} | } | ||||
@@ -37,17 +37,17 @@ public class QrCodeRequestExecutor implements RequestExecutor<File, AbstractWxMa | |||||
HttpPost httpPost = new HttpPost(uri); | HttpPost httpPost = new HttpPost(uri); | ||||
if (requestHttp.getRequestHttpProxy() != null) { | if (requestHttp.getRequestHttpProxy() != null) { | ||||
httpPost.setConfig( | httpPost.setConfig( | ||||
RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build() | |||||
RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build() | |||||
); | ); | ||||
} | } | ||||
httpPost.setEntity(new StringEntity(ticket.toString())); | |||||
httpPost.setEntity(new StringEntity(ticket.toJson())); | |||||
try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); | try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); | ||||
InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { | InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { | ||||
Header[] contentTypeHeader = response.getHeaders("Content-Type"); | Header[] contentTypeHeader = response.getHeaders("Content-Type"); | ||||
if (contentTypeHeader != null && contentTypeHeader.length > 0 | if (contentTypeHeader != null && contentTypeHeader.length > 0 | ||||
&& ContentType.APPLICATION_JSON.getMimeType() | |||||
.equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) { | |||||
&& ContentType.APPLICATION_JSON.getMimeType() | |||||
.equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) { | |||||
String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); | String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); | ||||
throw new WxErrorException(WxError.fromJson(responseContent)); | throw new WxErrorException(WxError.fromJson(responseContent)); | ||||
} | } | ||||
@@ -1,6 +1,5 @@ | |||||
package cn.binarywang.wx.miniapp.util.json; | package cn.binarywang.wx.miniapp.util.json; | ||||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; | import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; | ||||
import com.google.gson.Gson; | import com.google.gson.Gson; | ||||
import com.google.gson.GsonBuilder; | import com.google.gson.GsonBuilder; | ||||
@@ -13,7 +12,6 @@ public class WxMaGsonBuilder { | |||||
static { | static { | ||||
INSTANCE.disableHtmlEscaping(); | INSTANCE.disableHtmlEscaping(); | ||||
INSTANCE.registerTypeAdapter(WxMaKefuMessage.class, new WxMaKefuMessageGsonAdapter()); | |||||
INSTANCE.registerTypeAdapter(WxMaTemplateMessage.class, new WxMaTemplateMessageGsonAdapter()); | INSTANCE.registerTypeAdapter(WxMaTemplateMessage.class, new WxMaTemplateMessageGsonAdapter()); | ||||
} | } | ||||
@@ -1,46 +0,0 @@ | |||||
/* | |||||
* KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. | |||||
* | |||||
* This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended | |||||
* only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction | |||||
* arose from modification of the original source, or other redistribution of this source | |||||
* is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. | |||||
*/ | |||||
package cn.binarywang.wx.miniapp.util.json; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||||
import cn.binarywang.wx.miniapp.constant.WxMaConstants; | |||||
import com.google.gson.JsonElement; | |||||
import com.google.gson.JsonObject; | |||||
import com.google.gson.JsonSerializationContext; | |||||
import com.google.gson.JsonSerializer; | |||||
import java.lang.reflect.Type; | |||||
/** | |||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
*/ | |||||
public class WxMaKefuMessageGsonAdapter implements JsonSerializer<WxMaKefuMessage> { | |||||
@Override | |||||
public JsonElement serialize(WxMaKefuMessage message, Type typeOfSrc, JsonSerializationContext context) { | |||||
JsonObject messageJson = new JsonObject(); | |||||
messageJson.addProperty("touser", message.getToUser()); | |||||
messageJson.addProperty("msgtype", message.getMsgType()); | |||||
if (WxMaConstants.KefuMsgType.TEXT.equals(message.getMsgType())) { | |||||
JsonObject text = new JsonObject(); | |||||
text.addProperty("content", message.getContent()); | |||||
messageJson.add("text", text); | |||||
} | |||||
if (WxMaConstants.KefuMsgType.IMAGE.equals(message.getMsgType())) { | |||||
JsonObject image = new JsonObject(); | |||||
image.addProperty("media_id", message.getMediaId()); | |||||
messageJson.add("image", image); | |||||
} | |||||
return messageJson; | |||||
} | |||||
} |
@@ -1,12 +1,16 @@ | |||||
package cn.binarywang.wx.miniapp.util.xml; | package cn.binarywang.wx.miniapp.util.xml; | ||||
import java.io.InputStream; | |||||
import java.util.ArrayList; | |||||
import java.util.Arrays; | |||||
import java.util.HashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaMessage; | import cn.binarywang.wx.miniapp.bean.WxMaMessage; | ||||
import com.thoughtworks.xstream.XStream; | import com.thoughtworks.xstream.XStream; | ||||
import me.chanjar.weixin.common.util.xml.XStreamInitializer; | import me.chanjar.weixin.common.util.xml.XStreamInitializer; | ||||
import java.io.InputStream; | |||||
import java.util.*; | |||||
/** | /** | ||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
*/ | */ | ||||
@@ -45,7 +49,7 @@ public class XStreamTransformer { | |||||
* @param clz 类型 | * @param clz 类型 | ||||
* @param xStream xml解析器 | * @param xStream xml解析器 | ||||
*/ | */ | ||||
private static void register(Class<?> clz, XStream xStream) { | |||||
public static void register(Class<?> clz, XStream xStream) { | |||||
CLASS_2_XSTREAM_INSTANCE.put(clz, xStream); | CLASS_2_XSTREAM_INSTANCE.put(clz, xStream); | ||||
} | } | ||||
@@ -7,16 +7,14 @@ import cn.binarywang.wx.miniapp.test.ApiTestModule; | |||||
import cn.binarywang.wx.miniapp.test.TestConfig; | import cn.binarywang.wx.miniapp.test.TestConfig; | ||||
import com.google.common.collect.Lists; | import com.google.common.collect.Lists; | ||||
import com.google.inject.Inject; | import com.google.inject.Inject; | ||||
import me.chanjar.weixin.common.api.WxConsts; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
import org.testng.annotations.Guice; | |||||
import org.testng.annotations.Test; | |||||
import org.testng.annotations.*; | |||||
import java.text.SimpleDateFormat; | import java.text.SimpleDateFormat; | ||||
import java.util.Date; | import java.util.Date; | ||||
/** | /** | ||||
* 测试客服相关接口 | |||||
* 测试消息相关接口 | |||||
* | * | ||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
*/ | */ | ||||
@@ -25,26 +23,14 @@ import java.util.Date; | |||||
public class WxMaMsgServiceImplTest { | public class WxMaMsgServiceImplTest { | ||||
@Inject | @Inject | ||||
protected WxMaService wxService; | |||||
public void testSendKefuMpNewsMessage() throws WxErrorException { | |||||
TestConfig configStorage = (TestConfig) this.wxService | |||||
.getWxMaConfig(); | |||||
WxMaKefuMessage message = new WxMaKefuMessage(); | |||||
message.setMsgType(WxConsts.KefuMsgType.MPNEWS); | |||||
message.setToUser(configStorage.getOpenid()); | |||||
this.wxService.getMsgService().sendKefuMsg(message); | |||||
} | |||||
private WxMaService wxService; | |||||
public void testSendKefuMessage() throws WxErrorException { | public void testSendKefuMessage() throws WxErrorException { | ||||
TestConfig config = (TestConfig) this.wxService | |||||
.getWxMaConfig(); | |||||
WxMaKefuMessage message = new WxMaKefuMessage(); | |||||
message.setMsgType(WxConsts.KefuMsgType.TEXT); | |||||
message.setToUser(config.getOpenid()); | |||||
message.setContent( | |||||
"欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>"); | |||||
TestConfig config = (TestConfig) this.wxService.getWxMaConfig(); | |||||
WxMaKefuMessage message = WxMaKefuMessage.newTextBuilder() | |||||
.toUser(config.getOpenid()) | |||||
.content("欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>") | |||||
.build(); | |||||
this.wxService.getMsgService().sendKefuMsg(message); | this.wxService.getMsgService().sendKefuMsg(message); | ||||
} | } | ||||
@@ -66,7 +52,7 @@ public class WxMaMsgServiceImplTest { | |||||
.templateId(config.getTemplateId()) | .templateId(config.getTemplateId()) | ||||
.emphasisKeyword("keyword1.DATA") | .emphasisKeyword("keyword1.DATA") | ||||
.build(); | .build(); | ||||
//templateMessage.addData( new WxMaTemplateMessage.Data("keyword1", "339208499", "#173177")); | |||||
this.wxService.getMsgService().sendTemplateMsg(templateMessage); | this.wxService.getMsgService().sendTemplateMsg(templateMessage); | ||||
} | } | ||||
@@ -0,0 +1,70 @@ | |||||
package cn.binarywang.wx.miniapp.api.impl; | |||||
import cn.binarywang.wx.miniapp.api.WxMaService; | |||||
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateAddResult; | |||||
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryGetResult; | |||||
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryListResult; | |||||
import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateListResult; | |||||
import cn.binarywang.wx.miniapp.test.ApiTestModule; | |||||
import com.google.inject.Inject; | |||||
import org.assertj.core.util.Lists; | |||||
import org.testng.Assert; | |||||
import org.testng.annotations.Guice; | |||||
import org.testng.annotations.Test; | |||||
import java.util.List; | |||||
@Test | |||||
@Guice(modules = ApiTestModule.class) | |||||
public class WxMaTemplateServiceImplTest { | |||||
@Inject | |||||
protected WxMaService wxService; | |||||
@Test | |||||
public void testFindTemplateLibraryList() throws Exception { | |||||
WxMaTemplateLibraryListResult result = this.wxService.getTemplateService().findTemplateLibraryList(0, 20); | |||||
Assert.assertEquals(20, result.getList().size()); | |||||
} | |||||
@Test | |||||
public void testFindTemplateLibraryKeywordList() throws Exception { | |||||
WxMaTemplateLibraryGetResult result = this.wxService.getTemplateService().findTemplateLibraryKeywordList("AT0004"); | |||||
Assert.assertEquals("AT0004", result.getId()); | |||||
Assert.assertEquals("交易提醒", result.getTitle()); | |||||
Assert.assertEquals(100, result.getKeywordList().size()); | |||||
} | |||||
@Test | |||||
public void testAddTemplate() throws Exception{ | |||||
List<Integer> list = Lists.newArrayList(); | |||||
list.add(1); | |||||
list.add(20); | |||||
list.add(84); | |||||
WxMaTemplateAddResult result = this.wxService.getTemplateService().addTemplate("AT0004", list); | |||||
Assert.assertNotNull(result.getTemplateId()); | |||||
System.out.println(result); | |||||
} | |||||
@Test | |||||
public void testFindTemplateList() throws Exception{ | |||||
WxMaTemplateListResult result = this.wxService.getTemplateService().findTemplateList(0, 20); | |||||
System.out.println(result); | |||||
} | |||||
@Test | |||||
public void testDelTemplate() throws Exception { | |||||
//add | |||||
List<Integer> list = Lists.newArrayList(); | |||||
list.add(1); | |||||
list.add(20); | |||||
list.add(84); | |||||
WxMaTemplateAddResult result = this.wxService.getTemplateService().addTemplate("AT0004", list); | |||||
//delete | |||||
this.wxService.getTemplateService().delTemplate(result.getTemplateId()); | |||||
} | |||||
} |
@@ -1,14 +1,14 @@ | |||||
package cn.binarywang.wx.miniapp.api.impl; | package cn.binarywang.wx.miniapp.api.impl; | ||||
import org.testng.annotations.*; | |||||
import cn.binarywang.wx.miniapp.api.WxMaService; | import cn.binarywang.wx.miniapp.api.WxMaService; | ||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; | |||||
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; | import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; | ||||
import cn.binarywang.wx.miniapp.test.ApiTestModule; | import cn.binarywang.wx.miniapp.test.ApiTestModule; | ||||
import com.google.inject.Inject; | import com.google.inject.Inject; | ||||
import org.testng.annotations.Guice; | |||||
import org.testng.annotations.Test; | |||||
import static org.testng.Assert.assertNotNull; | |||||
import static org.testng.Assert.assertTrue; | |||||
import static org.testng.Assert.*; | |||||
/** | /** | ||||
* 测试用户相关的接口 | * 测试用户相关的接口 | ||||
@@ -28,7 +28,7 @@ public class WxMaUserServiceImplTest { | |||||
} | } | ||||
@Test | @Test | ||||
public void testGetUserInfo() throws Exception { | |||||
public void testGetUserInfo() { | |||||
WxMaUserInfo userInfo = this.wxService.getUserService().getUserInfo("tiihtNczf5v6AKRyjwEUhQ==", | WxMaUserInfo userInfo = this.wxService.getUserService().getUserInfo("tiihtNczf5v6AKRyjwEUhQ==", | ||||
"CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZMQmRzooG2xrDcvSnxIMXFufNstNGTyaGS9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+3hVbJSRgv+4lGOETKUQz6OYStslQ142dNCuabNPGBzlooOmB231qMM85d2/fV6ChevvXvQP8Hkue1poOFtnEtpyxVLW1zAo6/1Xx1COxFvrc2d7UL/lmHInNlxuacJXwu0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn/Hz7saL8xz+W//FRAUid1OksQaQx4CMs8LOddcQhULW4ucetDf96JcR3g0gfRK4PC7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns/8wR2SiRS7MNACwTyrGvt9ts8p12PKFdlqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYVoKlaRv85IfVunYzO0IKXsyl7JCUjCpoG20f0a04COwfneQAGGwd5oa+T8yO5hzuyDb/XcxxmK01EpqOyuxINew==", | "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZMQmRzooG2xrDcvSnxIMXFufNstNGTyaGS9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+3hVbJSRgv+4lGOETKUQz6OYStslQ142dNCuabNPGBzlooOmB231qMM85d2/fV6ChevvXvQP8Hkue1poOFtnEtpyxVLW1zAo6/1Xx1COxFvrc2d7UL/lmHInNlxuacJXwu0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn/Hz7saL8xz+W//FRAUid1OksQaQx4CMs8LOddcQhULW4ucetDf96JcR3g0gfRK4PC7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns/8wR2SiRS7MNACwTyrGvt9ts8p12PKFdlqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYVoKlaRv85IfVunYzO0IKXsyl7JCUjCpoG20f0a04COwfneQAGGwd5oa+T8yO5hzuyDb/XcxxmK01EpqOyuxINew==", | ||||
"r7BXXKkLb8qrSNn05n0qiA=="); | "r7BXXKkLb8qrSNn05n0qiA=="); | ||||
@@ -37,10 +37,21 @@ public class WxMaUserServiceImplTest { | |||||
} | } | ||||
@Test | @Test | ||||
public void testCheckUserInfo() throws Exception { | |||||
public void testCheckUserInfo() { | |||||
assertTrue(this.wxService.getUserService().checkUserInfo("HyVFkGl5F5OQWJZZaNzBBg==", | assertTrue(this.wxService.getUserService().checkUserInfo("HyVFkGl5F5OQWJZZaNzBBg==", | ||||
"{\"nickName\":\"Band\",\"gender\":1,\"language\":\"zh_CN\",\"city\":\"Guangzhou\",\"province\":\"Guangdong\",\"country\":\"CN\",\"avatarUrl\":\"http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0\"}", | "{\"nickName\":\"Band\",\"gender\":1,\"language\":\"zh_CN\",\"city\":\"Guangzhou\",\"province\":\"Guangdong\",\"country\":\"CN\",\"avatarUrl\":\"http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0\"}", | ||||
"75e81ceda165f4ffa64f4068af58c64b8f54b88c")); | "75e81ceda165f4ffa64f4068af58c64b8f54b88c")); | ||||
} | } | ||||
/** | |||||
* TODO 测试数据有问题,需要替换为正确的数据 | |||||
*/ | |||||
@Test | |||||
public void testGetPhoneNoInfo() { | |||||
WxMaPhoneNumberInfo phoneNoInfo = this.wxService.getUserService().getPhoneNoInfo("tiihtNczf5v6AKRyjwEUhQ==", | |||||
"CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZMQmRzooG2xrDcvSnxIMXFufNstNGTyaGS9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+3hVbJSRgv+4lGOETKUQz6OYStslQ142dNCuabNPGBzlooOmB231qMM85d2/fV6ChevvXvQP8Hkue1poOFtnEtpyxVLW1zAo6/1Xx1COxFvrc2d7UL/lmHInNlxuacJXwu0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn/Hz7saL8xz+W//FRAUid1OksQaQx4CMs8LOddcQhULW4ucetDf96JcR3g0gfRK4PC7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns/8wR2SiRS7MNACwTyrGvt9ts8p12PKFdlqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYVoKlaRv85IfVunYzO0IKXsyl7JCUjCpoG20f0a04COwfneQAGGwd5oa+T8yO5hzuyDb/XcxxmK01EpqOyuxINew==", | |||||
"r7BXXKkLb8qrSNn05n0qiA=="); | |||||
assertNotNull(phoneNoInfo); | |||||
System.out.println(phoneNoInfo.toString()); | |||||
} | |||||
} | } |
@@ -1,8 +1,8 @@ | |||||
package cn.binarywang.wx.miniapp.bean; | package cn.binarywang.wx.miniapp.bean; | ||||
import me.chanjar.weixin.common.api.WxConsts; | |||||
import org.testng.Assert; | |||||
import org.testng.annotations.Test; | |||||
import org.testng.annotations.*; | |||||
import static org.assertj.core.api.Assertions.assertThat; | |||||
/** | /** | ||||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
@@ -10,30 +10,47 @@ import org.testng.annotations.Test; | |||||
@Test | @Test | ||||
public class WxMaKefuMessageTest { | public class WxMaKefuMessageTest { | ||||
public void testTextReply() { | |||||
WxMaKefuMessage reply = new WxMaKefuMessage(); | |||||
reply.setToUser("OPENID"); | |||||
reply.setMsgType(WxConsts.KefuMsgType.TEXT); | |||||
reply.setContent("sfsfdsdf"); | |||||
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); | |||||
public void testTextBuilder() { | |||||
WxMaKefuMessage reply = WxMaKefuMessage.newTextBuilder() | |||||
.toUser("OPENID") | |||||
.content("sfsfdsdf") | |||||
.build(); | |||||
assertThat(reply.toJson()) | |||||
.isEqualTo("{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); | |||||
} | } | ||||
public void testTextBuild() { | |||||
WxMaKefuMessage reply = WxMaKefuMessage.newTextBuilder().toUser("OPENID").content("sfsfdsdf").build(); | |||||
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); | |||||
public void testImageBuilder() { | |||||
WxMaKefuMessage reply = WxMaKefuMessage.newImageBuilder() | |||||
.toUser("OPENID") | |||||
. mediaId("MEDIA_ID") | |||||
.build(); | |||||
assertThat(reply.toJson()) | |||||
.isEqualTo( "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); | |||||
} | } | ||||
public void testImageReply() { | |||||
WxMaKefuMessage reply = new WxMaKefuMessage(); | |||||
reply.setToUser("OPENID"); | |||||
reply.setMsgType(WxConsts.KefuMsgType.IMAGE); | |||||
reply.setMediaId("MEDIA_ID"); | |||||
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); | |||||
public void testLinkBuilder() { | |||||
WxMaKefuMessage reply = WxMaKefuMessage.newLinkBuilder() | |||||
.toUser("OPENID") | |||||
.url("url") | |||||
.description("description") | |||||
.title("title") | |||||
.thumbUrl("thumbUrl") | |||||
.build(); | |||||
assertThat(reply.toJson()) | |||||
.isEqualTo( "{\"touser\":\"OPENID\",\"msgtype\":\"link\"," + | |||||
"\"link\":{\"title\":\"title\",\"description\":\"description\",\"url\":\"url\",\"thumb_url\":\"thumbUrl\"}}"); | |||||
} | } | ||||
public void testImageBuild() { | |||||
WxMaKefuMessage reply = WxMaKefuMessage.newImageBuilder().toUser("OPENID").mediaId("MEDIA_ID").build(); | |||||
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); | |||||
public void testMaPageBuilder() { | |||||
WxMaKefuMessage reply = WxMaKefuMessage.newMaPageBuilder() | |||||
.toUser("OPENID") | |||||
.title("title") | |||||
.pagePath("pagePath") | |||||
.thumbMediaId("thumbMediaId") | |||||
.build(); | |||||
assertThat(reply.toJson()) | |||||
.isEqualTo( "{\"touser\":\"OPENID\",\"msgtype\":\"miniprogrampage\"," + | |||||
"\"miniprogrampage\":{\"title\":\"title\",\"pagepath\":\"pagePath\",\"thumb_media_id\":\"thumbMediaId\"}}"); | |||||
} | } | ||||
@@ -7,10 +7,10 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>weixin-java-parent</artifactId> | <artifactId>weixin-java-parent</artifactId> | ||||
<version>2.9.0</version> | |||||
<version>2.9.9.BETA</version> | |||||
</parent> | </parent> | ||||
<artifactId>weixin-java-mp</artifactId> | <artifactId>weixin-java-mp</artifactId> | ||||
<name>WeiXin Java Tools - MP</name> | |||||
<name>Weixin Java Tools - MP</name> | |||||
<description>微信公众号Java SDK</description> | <description>微信公众号Java SDK</description> | ||||
<dependencies> | <dependencies> | ||||
@@ -65,6 +65,15 @@ | |||||
<artifactId>logback-classic</artifactId> | <artifactId>logback-classic</artifactId> | ||||
<scope>test</scope> | <scope>test</scope> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>org.assertj</groupId> | |||||
<artifactId>assertj-guava</artifactId> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.projectlombok</groupId> | |||||
<artifactId>lombok</artifactId> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
<build> | <build> | ||||
@@ -85,6 +85,8 @@ public interface WxMpConfigStorage { | |||||
String getAesKey(); | String getAesKey(); | ||||
String getTemplateId(); | |||||
long getExpiresTime(); | long getExpiresTime(); | ||||
String getOauth2redirectUri(); | String getOauth2redirectUri(); | ||||
@@ -18,6 +18,7 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||||
protected volatile String appId; | protected volatile String appId; | ||||
protected volatile String secret; | protected volatile String secret; | ||||
protected volatile String token; | protected volatile String token; | ||||
protected volatile String templateId; | |||||
protected volatile String accessToken; | protected volatile String accessToken; | ||||
protected volatile String aesKey; | protected volatile String aesKey; | ||||
protected volatile long expiresTime; | protected volatile long expiresTime; | ||||
@@ -173,6 +174,15 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||||
this.token = token; | this.token = token; | ||||
} | } | ||||
@Override | |||||
public String getTemplateId() { | |||||
return this.templateId; | |||||
} | |||||
public void setTemplateId(String templateId) { | |||||
this.templateId = templateId; | |||||
} | |||||
@Override | @Override | ||||
public long getExpiresTime() { | public long getExpiresTime() { | ||||
return this.expiresTime; | return this.expiresTime; | ||||
@@ -51,7 +51,7 @@ public class WxMpInRedisConfigStorage extends WxMpInMemoryConfigStorage { | |||||
@Override | @Override | ||||
public String getAccessToken() { | public String getAccessToken() { | ||||
try (Jedis jedis = this.jedisPool.getResource()) { | try (Jedis jedis = this.jedisPool.getResource()) { | ||||
return jedis.get(accessTokenKey); | |||||
return jedis.get(this.accessTokenKey); | |||||
} | } | ||||
} | } | ||||
@@ -65,70 +65,70 @@ public class WxMpInRedisConfigStorage extends WxMpInMemoryConfigStorage { | |||||
@Override | @Override | ||||
public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { | public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { | ||||
try (Jedis jedis = this.jedisPool.getResource()) { | try (Jedis jedis = this.jedisPool.getResource()) { | ||||
jedis.setex(accessTokenKey, expiresInSeconds - 200, accessToken); | |||||
jedis.setex(this.accessTokenKey, expiresInSeconds - 200, accessToken); | |||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
public void expireAccessToken() { | public void expireAccessToken() { | ||||
try (Jedis jedis = this.jedisPool.getResource()) { | try (Jedis jedis = this.jedisPool.getResource()) { | ||||
jedis.expire(accessTokenKey, 0); | |||||
jedis.expire(this.accessTokenKey, 0); | |||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
public String getJsapiTicket() { | public String getJsapiTicket() { | ||||
try (Jedis jedis = this.jedisPool.getResource()) { | try (Jedis jedis = this.jedisPool.getResource()) { | ||||
return jedis.get(jsapiTicketKey); | |||||
return jedis.get(this.jsapiTicketKey); | |||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
public boolean isJsapiTicketExpired() { | public boolean isJsapiTicketExpired() { | ||||
try (Jedis jedis = this.jedisPool.getResource()) { | try (Jedis jedis = this.jedisPool.getResource()) { | ||||
return jedis.ttl(jsapiTicketKey) < 2; | |||||
return jedis.ttl(this.jsapiTicketKey) < 2; | |||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { | public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { | ||||
try (Jedis jedis = this.jedisPool.getResource()) { | try (Jedis jedis = this.jedisPool.getResource()) { | ||||
jedis.setex(jsapiTicketKey, expiresInSeconds - 200, jsapiTicket); | |||||
jedis.setex(this.jsapiTicketKey, expiresInSeconds - 200, jsapiTicket); | |||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
public void expireJsapiTicket() { | public void expireJsapiTicket() { | ||||
try (Jedis jedis = this.jedisPool.getResource()) { | try (Jedis jedis = this.jedisPool.getResource()) { | ||||
jedis.expire(jsapiTicketKey, 0); | |||||
jedis.expire(this.jsapiTicketKey, 0); | |||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
public String getCardApiTicket() { | public String getCardApiTicket() { | ||||
try (Jedis jedis = this.jedisPool.getResource()) { | try (Jedis jedis = this.jedisPool.getResource()) { | ||||
return jedis.get(cardapiTicketKey); | |||||
return jedis.get(this.cardapiTicketKey); | |||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
public boolean isCardApiTicketExpired() { | public boolean isCardApiTicketExpired() { | ||||
try (Jedis jedis = this.jedisPool.getResource()) { | try (Jedis jedis = this.jedisPool.getResource()) { | ||||
return jedis.ttl(cardapiTicketKey) < 2; | |||||
return jedis.ttl(this.cardapiTicketKey) < 2; | |||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
public synchronized void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { | public synchronized void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { | ||||
try (Jedis jedis = this.jedisPool.getResource()) { | try (Jedis jedis = this.jedisPool.getResource()) { | ||||
jedis.setex(cardapiTicketKey, expiresInSeconds - 200, cardApiTicket); | |||||
jedis.setex(this.cardapiTicketKey, expiresInSeconds - 200, cardApiTicket); | |||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
public void expireCardApiTicket() { | public void expireCardApiTicket() { | ||||
try (Jedis jedis = this.jedisPool.getResource()) { | try (Jedis jedis = this.jedisPool.getResource()) { | ||||
jedis.expire(cardapiTicketKey, 0); | |||||
jedis.expire(this.cardapiTicketKey, 0); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -7,7 +7,7 @@ import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 群发消息服务类 | |||||
* 群发消息服务类. | |||||
* Created by Binary Wang on 2017-8-16. | * Created by Binary Wang on 2017-8-16. | ||||
* </pre> | * </pre> | ||||
* | * | ||||
@@ -15,33 +15,33 @@ import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult; | |||||
*/ | */ | ||||
public interface WxMpMassMessageService { | public interface WxMpMassMessageService { | ||||
/** | /** | ||||
* 上传群发用的图文消息 | |||||
* 上传群发用的图文消息. | |||||
*/ | */ | ||||
String MEDIA_UPLOAD_NEWS_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; | String MEDIA_UPLOAD_NEWS_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; | ||||
/** | /** | ||||
* 上传群发用的视频 | |||||
* 上传群发用的视频. | |||||
*/ | */ | ||||
String MEDIA_UPLOAD_VIDEO_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo"; | String MEDIA_UPLOAD_VIDEO_URL = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo"; | ||||
/** | /** | ||||
* 分组群发消息 | |||||
* 分组群发消息. | |||||
*/ | */ | ||||
String MESSAGE_MASS_SENDALL_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"; | String MESSAGE_MASS_SENDALL_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"; | ||||
/** | /** | ||||
* 按openId列表群发消息 | |||||
* 按openId列表群发消息. | |||||
*/ | */ | ||||
String MESSAGE_MASS_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/send"; | String MESSAGE_MASS_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/send"; | ||||
/** | /** | ||||
* 群发消息预览接口 | |||||
* 群发消息预览接口. | |||||
*/ | */ | ||||
String MESSAGE_MASS_PREVIEW_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; | String MESSAGE_MASS_PREVIEW_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/preview"; | ||||
/** | /** | ||||
* 删除群发接口 | |||||
* 删除群发接口. | |||||
*/ | */ | ||||
String MESSAGE_MASS_DELETE_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/delete"; | String MESSAGE_MASS_DELETE_URL = "https://api.weixin.qq.com/cgi-bin/message/mass/delete"; | ||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 上传群发用的图文消息,上传后才能群发图文消息 | |||||
* 上传群发用的图文消息,上传后才能群发图文消息. | |||||
* | * | ||||
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN | * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN | ||||
* </pre> | * </pre> | ||||
@@ -53,7 +53,7 @@ public interface WxMpMassMessageService { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 上传群发用的视频,上传后才能群发视频消息 | |||||
* 上传群发用的视频,上传后才能群发视频消息. | |||||
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN | * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN | ||||
* </pre> | * </pre> | ||||
* | * | ||||
@@ -64,7 +64,7 @@ public interface WxMpMassMessageService { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 分组群发消息 | |||||
* 分组群发消息. | |||||
* 如果发送图文消息,必须先使用 {@link #massNewsUpload(WxMpMassNews)} 获得media_id,然后再发送 | * 如果发送图文消息,必须先使用 {@link #massNewsUpload(WxMpMassNews)} 获得media_id,然后再发送 | ||||
* 如果发送视频消息,必须先使用 {@link #massVideoUpload(WxMpMassVideo)} 获得media_id,然后再发送 | * 如果发送视频消息,必须先使用 {@link #massVideoUpload(WxMpMassVideo)} 获得media_id,然后再发送 | ||||
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN | * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN | ||||
@@ -74,7 +74,7 @@ public interface WxMpMassMessageService { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 按openId列表群发消息 | |||||
* 按openId列表群发消息. | |||||
* 如果发送图文消息,必须先使用 {@link #massNewsUpload(WxMpMassNews)} 获得media_id,然后再发送 | * 如果发送图文消息,必须先使用 {@link #massNewsUpload(WxMpMassNews)} 获得media_id,然后再发送 | ||||
* 如果发送视频消息,必须先使用 {@link #massVideoUpload(WxMpMassVideo)} 获得media_id,然后再发送 | * 如果发送视频消息,必须先使用 {@link #massVideoUpload(WxMpMassVideo)} 获得media_id,然后再发送 | ||||
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN | * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN | ||||
@@ -84,7 +84,7 @@ public interface WxMpMassMessageService { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 群发消息预览接口 | |||||
* 群发消息预览接口. | |||||
* 开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版。为了满足第三方平台开发者的需求,在保留对openID预览能力的同时,增加了对指定微信号发送预览的能力,但该能力每日调用次数有限制(100次),请勿滥用。 | * 开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版。为了满足第三方平台开发者的需求,在保留对openID预览能力的同时,增加了对指定微信号发送预览的能力,但该能力每日调用次数有限制(100次),请勿滥用。 | ||||
* 接口调用请求说明 | * 接口调用请求说明 | ||||
* http请求方式: POST | * http请求方式: POST | ||||
@@ -98,7 +98,7 @@ public interface WxMpMassMessageService { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 删除群发 | |||||
* 删除群发. | |||||
* 群发之后,随时可以通过该接口删除群发。 | * 群发之后,随时可以通过该接口删除群发。 | ||||
* 请注意: | * 请注意: | ||||
* 1、只有已经发送成功的消息才能删除 | * 1、只有已经发送成功的消息才能删除 | ||||
@@ -114,6 +114,6 @@ public interface WxMpMassMessageService { | |||||
* @param msgId 发送出去的消息ID | * @param msgId 发送出去的消息ID | ||||
* @param articleIndex 要删除的文章在图文消息中的位置,第一篇编号为1,该字段不填或填0会删除全部文章 | * @param articleIndex 要删除的文章在图文消息中的位置,第一篇编号为1,该字段不填或填0会删除全部文章 | ||||
*/ | */ | ||||
void delete(Integer msgId, Integer articleIndex) throws WxErrorException; | |||||
void delete(Long msgId, Integer articleIndex) throws WxErrorException; | |||||
} | } |
@@ -130,6 +130,16 @@ public class WxMpMessageRouter { | |||||
* 处理微信消息 | * 处理微信消息 | ||||
*/ | */ | ||||
public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage, final Map<String, Object> context) { | public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage, final Map<String, Object> context) { | ||||
return route(wxMessage, context, null); | |||||
} | |||||
/** | |||||
* 处理微信消息 | |||||
*/ | |||||
public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage, final Map<String, Object> context, WxMpService wxMpService) { | |||||
if(wxMpService == null){ | |||||
wxMpService = this.wxMpService; | |||||
} | |||||
final WxMpService mpService = wxMpService; | |||||
if (isMsgDuplicated(wxMessage)) { | if (isMsgDuplicated(wxMessage)) { | ||||
// 如果是重复消息,那么就不做处理 | // 如果是重复消息,那么就不做处理 | ||||
return null; | return null; | ||||
@@ -159,12 +169,12 @@ public class WxMpMessageRouter { | |||||
this.executorService.submit(new Runnable() { | this.executorService.submit(new Runnable() { | ||||
@Override | @Override | ||||
public void run() { | public void run() { | ||||
rule.service(wxMessage, context, WxMpMessageRouter.this.wxMpService, WxMpMessageRouter.this.sessionManager, WxMpMessageRouter.this.exceptionHandler); | |||||
rule.service(wxMessage, context, mpService, WxMpMessageRouter.this.sessionManager, WxMpMessageRouter.this.exceptionHandler); | |||||
} | } | ||||
}) | }) | ||||
); | ); | ||||
} else { | } else { | ||||
res = rule.service(wxMessage, context, this.wxMpService, this.sessionManager, this.exceptionHandler); | |||||
res = rule.service(wxMessage, context, mpService, this.sessionManager, this.exceptionHandler); | |||||
// 在同步操作结束,session访问结束 | // 在同步操作结束,session访问结束 | ||||
this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser()); | this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser()); | ||||
sessionEndAccess(wxMessage); | sessionEndAccess(wxMessage); | ||||
@@ -90,7 +90,7 @@ public interface WxMpService { | |||||
* 获取access_token,本方法线程安全 | * 获取access_token,本方法线程安全 | ||||
* 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限 | * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限 | ||||
* | * | ||||
* 另:本service的所有方法都会在access_token过期是调用此方法 | |||||
* 另:本service的所有方法都会在access_token过期时调用此方法 | |||||
* | * | ||||
* 程序员在非必要情况下尽量不要主动调用此方法 | * 程序员在非必要情况下尽量不要主动调用此方法 | ||||
* | * | ||||
@@ -363,6 +363,13 @@ public interface WxMpService { | |||||
*/ | */ | ||||
WxMpTemplateMsgService getTemplateMsgService(); | WxMpTemplateMsgService getTemplateMsgService(); | ||||
/** | |||||
* 返回一次性订阅消息相关接口方法的实现类对象,以方便调用其各个接口 | |||||
* | |||||
* @return WxMpSubscribeMsgService | |||||
*/ | |||||
WxMpSubscribeMsgService getSubscribeMsgService(); | |||||
/** | /** | ||||
* 返回硬件平台相关接口方法的实现类对象,以方便调用其各个接口 | * 返回硬件平台相关接口方法的实现类对象,以方便调用其各个接口 | ||||
* | * | ||||
@@ -0,0 +1,40 @@ | |||||
package me.chanjar.weixin.mp.api; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.mp.bean.subscribe.WxMpSubscribeMessage; | |||||
/** | |||||
* <pre> | |||||
* 一次性订阅消息接口 | |||||
* https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1500374289_66bvB | |||||
* </pre> | |||||
* | |||||
* @author Mklaus | |||||
* @date 2018-01-22 上午11:07 | |||||
*/ | |||||
public interface WxMpSubscribeMsgService { | |||||
/** | |||||
* <pre> | |||||
* 构造用户订阅一条模板消息授权的url连接 | |||||
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1500374289_66bvB | |||||
* </pre> | |||||
* | |||||
* @param redirectURI 用户授权完成后的重定向链接,无需urlencode, 方法内会进行encode | |||||
* @param scene 重定向后会带上scene参数,开发者可以填0-10000的整形值,用来标识订阅场景值 | |||||
* @param reserved 用于保持请求和回调的状态,授权请后原样带回给第三方 (最多128字节,要求做urlencode) | |||||
* @return url | |||||
*/ | |||||
String subscribeMsgAuthorizationUrl(String redirectURI, int scene, String reserved); | |||||
/** | |||||
* <pre> | |||||
* 发送一次性订阅消息 | |||||
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1500374289_66bvB | |||||
* </pre> | |||||
* | |||||
* @return 消息Id | |||||
*/ | |||||
boolean sendSubscribeMessage(WxMpSubscribeMessage message) throws WxErrorException; | |||||
} |
@@ -213,7 +213,7 @@ public class WxMpCardServiceImpl implements WxMpCardService { | |||||
WxMpCardResult cardResult = WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, | WxMpCardResult cardResult = WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement, | ||||
new TypeToken<WxMpCardResult>() { | new TypeToken<WxMpCardResult>() { | ||||
}.getType()); | }.getType()); | ||||
if (!cardResult.getErrorCode().equals("0")) { | |||||
if (!"0".equals(cardResult.getErrorCode())) { | |||||
this.log.warn("朋友的券mark失败:{}", cardResult.getErrorMsg()); | this.log.warn("朋友的券mark失败:{}", cardResult.getErrorMsg()); | ||||
} | } | ||||
} | } | ||||
@@ -57,7 +57,7 @@ public class WxMpMassMessageServiceImpl implements WxMpMassMessageService { | |||||
} | } | ||||
@Override | @Override | ||||
public void delete(Integer msgId, Integer articleIndex) throws WxErrorException { | |||||
public void delete(Long msgId, Integer articleIndex) throws WxErrorException { | |||||
JsonObject jsonObject = new JsonObject(); | JsonObject jsonObject = new JsonObject(); | ||||
jsonObject.addProperty("msg_id", msgId); | jsonObject.addProperty("msg_id", msgId); | ||||
jsonObject.addProperty("article_idx", articleIndex); | jsonObject.addProperty("article_idx", articleIndex); | ||||