first commit

first commit
master
zifangsky 6 years ago
parent e57db71437
commit f43ff60c98

41
.gitignore vendored

@ -1,22 +1,25 @@
# Compiled class file
*.class
*/target/*
!.mvn/wrapper/maven-wrapper.jar
# Log file
*.log
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
# BlueJ files
*.ctxt
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/

@ -0,0 +1,25 @@
/target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

Binary file not shown.

@ -0,0 +1 @@
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip

225
ClientDemo/mvnw vendored

@ -0,0 +1,225 @@
#!/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
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
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() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
echo $MAVEN_PROJECTBASEDIR
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
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

143
ClientDemo/mvnw.cmd vendored

@ -0,0 +1,143 @@
@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
@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
%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%

@ -0,0 +1,165 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.zifangsky</groupId>
<artifactId>clientdemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ClientDemo</name>
<description>Demo project for License</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- 打包时忽略测试代码 -->
<skipTests>true</skipTests>
<!-- JUnit单元测试 -->
<junit>4.12</junit>
<!-- Apache Commons系列公共库 -->
<commons-lang3>3.7</commons-lang3>
<commons-io>2.6</commons-io>
<commons-codec>1.11</commons-codec>
<!-- Apache HttpClient -->
<httpclient>4.5.5</httpclient>
<!-- Fastjson -->
<fastjson>1.2.47</fastjson>
<!-- Java Servlet API -->
<javax.servlet-api>4.0.1</javax.servlet-api>
<!-- License -->
<truelicense>1.33</truelicense>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit}</version>
<scope>test</scope>
</dependency>
<!-- Commons -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec}</version>
</dependency>
<!-- Apache HttpClient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient}</version>
</dependency>
<!-- Fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson}</version>
</dependency>
<!-- Java Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${javax.servlet-api}</version>
<scope>provided</scope>
</dependency>
<!-- Jackson对自动解析JSON和XML格式的支持 -->
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<!-- SLF4J和LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<!-- License -->
<dependency>
<groupId>de.schlichtherle.truelicense</groupId>
<artifactId>truelicense-core</artifactId>
<version>${truelicense}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.tld</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>

@ -0,0 +1,19 @@
package cn.zifangsky;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.PropertySource;
@SpringBootApplication
@ServletComponentScan
@PropertySource({"license-config.properties"}) //加载额外的配置
public class ClientDemoApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(ClientDemoApplication.class);
application.setBannerMode(Banner.Mode.CONSOLE);
application.run(args);
}
}

@ -0,0 +1,72 @@
package cn.zifangsky.common;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* Spring
* @author zifangsky
*/
@Component
public class SpringContextUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
applicationContext = context;
}
/**
* ApplicationContext
* @return
*/
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
/**
* beanbean
* @param name
* @return
*/
public static Object getBeanByName(String name){
return applicationContext.getBean(name);
}
/**
* beanclass
* @param <T>
* @param c
* @return
*/
public static <T> T getBeanByClass(Class<T> c){
return applicationContext.getBean(c);
}
/**
* beanclass
* @param <T>
* @param c
* @return
*/
public static <T> Map<String, T> getBeansByClass(Class<T> c){
return applicationContext.getBeansOfType(c);
}
/**
* HttpServletRequest
* @return
*/
public static HttpServletRequest getRequest() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = attributes.getRequest();
return request;
}
}

@ -0,0 +1,94 @@
package cn.zifangsky.config;
import org.apache.http.Header;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Configuration
public class RestTemplateConfig {
/**
* RestTemplate
* @param factory ClientHttpRequestFactory
* @return RestTemplate
*/
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory){
return new RestTemplate(factory);
}
/**
* ClientHttpRequestFactory
* SimpleClientHttpRequestFactory使java.netHttp
* @return
*/
// @Bean
// public SimpleClientHttpRequestFactory simpleClientHttpRequestFactory(){
// SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
//
// requestFactory.setReadTimeout(5000);
// requestFactory.setConnectTimeout(5000);
//
// return requestFactory;
// }
/**
* ClientHttpRequestFactory使
* HttpComponentsClientHttpRequestFactory使HttpclientHttp
* @return HttpComponentsClientHttpRequestFactory
*/
@Bean
public HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory(){
//Httpclient连接池长连接保持30秒
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
//设置总连接数
connectionManager.setMaxTotal(1000);
//设置同路由的并发数
connectionManager.setDefaultMaxPerRoute(1000);
//设置header
List<Header> headers = new ArrayList<Header>();
headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04"));
headers.add(new BasicHeader("Accept-Encoding", "gzip, deflate"));
headers.add(new BasicHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"));
headers.add(new BasicHeader("Connection", "keep-alive"));
//创建HttpClient
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.setDefaultHeaders(headers)
.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) //设置重试次数
.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()) //设置保持长连接
.build();
//创建HttpComponentsClientHttpRequestFactory实例
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory(httpClient);
//设置客户端和服务端建立连接的超时时间
requestFactory.setConnectTimeout(5000);
//设置客户端从服务端读取数据的超时时间
requestFactory.setReadTimeout(5000);
//设置从连接池获取连接的超时时间,不宜过长
requestFactory.setConnectionRequestTimeout(200);
//缓冲请求数据默认为true。通过POST或者PUT大量发送数据时建议将此更改为false以免耗尽内存
requestFactory.setBufferRequestBody(false);
return requestFactory;
}
}

@ -0,0 +1,34 @@
package cn.zifangsky.config;
import cn.zifangsky.license.LicenseCheckInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Web
* @author zifangsky
* @date 2018/7/9
* @since 1.0.0
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
*
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index").setViewName("index");
registry.addViewController("/login").setViewName("login");
}
/**
*
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LicenseCheckInterceptor()).addPathPatterns("/check");
}
}

@ -0,0 +1,56 @@
package cn.zifangsky.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author zifangsky
* @date 2018/7/9
* @since 1.0.0
*/
@Controller
public class LoginController {
/**
*
* @author zifangsky
* @date 2018/7/9 17:09
* @since 1.0.0
* @param username
* @param password
* @return java.util.Map<java.lang.String,java.lang.Object>
*/
@PostMapping("/check")
@ResponseBody
public Map<String,Object> test(@RequestParam(required = true) String username, @RequestParam(required = true) String password){
Map<String,Object> result = new HashMap<>(1);
System.out.println(MessageFormat.format("用户名:{0},密码:{1}",username,password));
//模拟登录
System.out.println("模拟登录流程");
result.put("code",200);
return result;
}
/**
*
* @author zifangsky
* @date 2018/7/9 17:10
* @since 1.0.0
* @return java.lang.String
*/
@RequestMapping("/userIndex")
public String userIndex(){
return "userIndex";
}
}

@ -0,0 +1,144 @@
package cn.zifangsky.license;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
/**
* IPMacCPU
*
* @author zifangsky
* @date 2018/4/23
* @since 1.0.0
*/
public abstract class AbstractServerInfos {
private static Logger logger = LogManager.getLogger(AbstractServerInfos.class);
/**
* License
* @author zifangsky
* @date 2018/4/23 14:23
* @since 1.0.0
* @return demo.LicenseCheckModel
*/
public LicenseCheckModel getServerInfos(){
LicenseCheckModel result = new LicenseCheckModel();
try {
result.setIpAddress(this.getIpAddress());
result.setMacAddress(this.getMacAddress());
result.setCpuSerial(this.getCPUSerial());
result.setMainBoardSerial(this.getMainBoardSerial());
}catch (Exception e){
logger.error("获取服务器硬件信息失败",e);
}
return result;
}
/**
* IP
* @author zifangsky
* @date 2018/4/23 11:32
* @since 1.0.0
* @return java.util.List<java.lang.String>
*/
protected abstract List<String> getIpAddress() throws Exception;
/**
* Mac
* @author zifangsky
* @date 2018/4/23 11:32
* @since 1.0.0
* @return java.util.List<java.lang.String>
*/
protected abstract List<String> getMacAddress() throws Exception;
/**
* CPU
* @author zifangsky
* @date 2018/4/23 11:35
* @since 1.0.0
* @return java.lang.String
*/
protected abstract String getCPUSerial() throws Exception;
/**
*
* @author zifangsky
* @date 2018/4/23 11:35
* @since 1.0.0
* @return java.lang.String
*/
protected abstract String getMainBoardSerial() throws Exception;
/**
* InetAddress
* @author zifangsky
* @date 2018/4/23 17:38
* @since 1.0.0
* @return java.util.List<java.net.InetAddress>
*/
protected List<InetAddress> getLocalAllInetAddress() throws Exception {
List<InetAddress> result = new ArrayList<>(4);
// 遍历所有的网络接口
for (Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); networkInterfaces.hasMoreElements(); ) {
NetworkInterface iface = (NetworkInterface) networkInterfaces.nextElement();
// 在所有的接口下再遍历IP
for (Enumeration inetAddresses = iface.getInetAddresses(); inetAddresses.hasMoreElements(); ) {
InetAddress inetAddr = (InetAddress) inetAddresses.nextElement();
//排除LoopbackAddress、SiteLocalAddress、LinkLocalAddress、MulticastAddress类型的IP地址
if(!inetAddr.isLoopbackAddress() /*&& !inetAddr.isSiteLocalAddress()*/
&& !inetAddr.isLinkLocalAddress() && !inetAddr.isMulticastAddress()){
result.add(inetAddr);
}
}
}
return result;
}
/**
* Mac
* @author zifangsky
* @date 2018/4/23 18:08
* @since 1.0.0
* @param
* @return void
*/
protected String getMacByInetAddress(InetAddress inetAddr){
try {
byte[] mac = NetworkInterface.getByInetAddress(inetAddr).getHardwareAddress();
StringBuffer stringBuffer = new StringBuffer();
for(int i=0;i<mac.length;i++){
if(i != 0) {
stringBuffer.append("-");
}
//将十六进制byte转化为字符串
String temp = Integer.toHexString(mac[i] & 0xff);
if(temp.length() == 1){
stringBuffer.append("0" + temp);
}else{
stringBuffer.append(temp);
}
}
return stringBuffer.toString().toUpperCase();
} catch (SocketException e) {
e.printStackTrace();
}
return null;
}
}

@ -0,0 +1,70 @@
package cn.zifangsky.license;
import de.schlichtherle.license.AbstractKeyStoreParam;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
* KeyStoreParam
*
* @author zifangsky
* @date 2018/4/26
* @since 1.0.0
*/
public class CustomKeyStoreParam extends AbstractKeyStoreParam {
/**
* /
*/
private String storePath;
private String alias;
private String storePwd;
private String keyPwd;
public CustomKeyStoreParam(Class clazz, String resource,String alias,String storePwd,String keyPwd) {
super(clazz, resource);
this.storePath = resource;
this.alias = alias;
this.storePwd = storePwd;
this.keyPwd = keyPwd;
}
@Override
public String getAlias() {
return alias;
}
@Override
public String getStorePwd() {
return storePwd;
}
@Override
public String getKeyPwd() {
return keyPwd;
}
/**
* de.schlichtherle.license.AbstractKeyStoreParamgetStream()<br/>
*
* @author zifangsky
* @date 2018/4/26 18:28
* @since 1.0.0
* @param
* @return java.io.InputStream
*/
@Override
public InputStream getStream() throws IOException {
final InputStream in = new FileInputStream(new File(storePath));
if (null == in){
throw new FileNotFoundException(storePath);
}
return in;
}
}

@ -0,0 +1,292 @@
package cn.zifangsky.license;
import de.schlichtherle.license.LicenseContent;
import de.schlichtherle.license.LicenseContentException;
import de.schlichtherle.license.LicenseManager;
import de.schlichtherle.license.LicenseNotary;
import de.schlichtherle.license.LicenseParam;
import de.schlichtherle.license.NoLicenseInstalledException;
import de.schlichtherle.xml.GenericCertificate;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;
/**
* LicenseManager
*
* @author zifangsky
* @date 2018/4/23
* @since 1.0.0
*/
public class CustomLicenseManager extends LicenseManager{
private static Logger logger = LogManager.getLogger(CustomLicenseManager.class);
//XML编码
private static final String XML_CHARSET = "UTF-8";
//默认BUFSIZE
private static final int DEFAULT_BUFSIZE = 8 * 1024;
public CustomLicenseManager() {
}
public CustomLicenseManager(LicenseParam param) {
super(param);
}
/**
* create
* @author zifangsky
* @date 2018/4/23 10:36
* @since 1.0.0
* @param
* @return byte[]
*/
@Override
protected synchronized byte[] create(
LicenseContent content,
LicenseNotary notary)
throws Exception {
initialize(content);
this.validateCreate(content);
final GenericCertificate certificate = notary.sign(content);
return getPrivacyGuard().cert2key(certificate);
}
/**
* installvalidatevalidateIPMac
* @author zifangsky
* @date 2018/4/23 10:40
* @since 1.0.0
* @param
* @return de.schlichtherle.license.LicenseContent
*/
@Override
protected synchronized LicenseContent install(
final byte[] key,
final LicenseNotary notary)
throws Exception {
final GenericCertificate certificate = getPrivacyGuard().key2cert(key);
notary.verify(certificate);
final LicenseContent content = (LicenseContent)this.load(certificate.getEncoded());
this.validate(content);
setLicenseKey(key);
setCertificate(certificate);
return content;
}
/**
* verifyvalidateIPMac
* @author zifangsky
* @date 2018/4/23 10:40
* @since 1.0.0
* @param
* @return de.schlichtherle.license.LicenseContent
*/
@Override
protected synchronized LicenseContent verify(final LicenseNotary notary)
throws Exception {
GenericCertificate certificate = getCertificate();
// Load license key from preferences,
final byte[] key = getLicenseKey();
if (null == key){
throw new NoLicenseInstalledException(getLicenseParam().getSubject());
}
certificate = getPrivacyGuard().key2cert(key);
notary.verify(certificate);
final LicenseContent content = (LicenseContent)this.load(certificate.getEncoded());
this.validate(content);
setCertificate(certificate);
return content;
}
/**
*
* @author zifangsky
* @date 2018/5/2 15:43
* @since 1.0.0
* @param content
*/
protected synchronized void validateCreate(final LicenseContent content)
throws LicenseContentException {
final LicenseParam param = getLicenseParam();
final Date now = new Date();
final Date notBefore = content.getNotBefore();
final Date notAfter = content.getNotAfter();
if (null != notAfter && now.after(notAfter)){
throw new LicenseContentException("证书失效时间不能早于当前时间");
}
if (null != notBefore && null != notAfter && notAfter.before(notBefore)){
throw new LicenseContentException("证书生效时间不能晚于证书失效时间");
}
final String consumerType = content.getConsumerType();
if (null == consumerType){
throw new LicenseContentException("用户类型不能为空");
}
}
/**
* validateIPMac
* @author zifangsky
* @date 2018/4/23 10:40
* @since 1.0.0
* @param content LicenseContent
*/
@Override
protected synchronized void validate(final LicenseContent content)
throws LicenseContentException {
//1. 首先调用父类的validate方法
super.validate(content);
//2. 然后校验自定义的License参数
//License中可被允许的参数信息
LicenseCheckModel expectedCheckModel = (LicenseCheckModel) content.getExtra();
//当前服务器真实的参数信息
LicenseCheckModel serverCheckModel = getServerInfos();
if(expectedCheckModel != null && serverCheckModel != null){
//校验IP地址
if(!checkIpAddress(expectedCheckModel.getIpAddress(),serverCheckModel.getIpAddress())){
throw new LicenseContentException("当前服务器的IP没在授权范围内");
}
//校验Mac地址
if(!checkIpAddress(expectedCheckModel.getMacAddress(),serverCheckModel.getMacAddress())){
throw new LicenseContentException("当前服务器的Mac地址没在授权范围内");
}
//校验主板序列号
if(!checkSerial(expectedCheckModel.getMainBoardSerial(),serverCheckModel.getMainBoardSerial())){
throw new LicenseContentException("当前服务器的主板序列号没在授权范围内");
}
//校验CPU序列号
if(!checkSerial(expectedCheckModel.getCpuSerial(),serverCheckModel.getCpuSerial())){
throw new LicenseContentException("当前服务器的CPU序列号没在授权范围内");
}
}else{
throw new LicenseContentException("不能获取服务器硬件信息");
}
}
/**
* XMLDecoderXML
* @author zifangsky
* @date 2018/4/25 14:02
* @since 1.0.0
* @param encoded XML
* @return java.lang.Object
*/
private Object load(String encoded){
BufferedInputStream inputStream = null;
XMLDecoder decoder = null;
try {
inputStream = new BufferedInputStream(new ByteArrayInputStream(encoded.getBytes(XML_CHARSET)));
decoder = new XMLDecoder(new BufferedInputStream(inputStream, DEFAULT_BUFSIZE),null,null);
return decoder.readObject();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} finally {
try {
if(decoder != null){
decoder.close();
}
if(inputStream != null){
inputStream.close();
}
} catch (Exception e) {
logger.error("XMLDecoder解析XML失败",e);
}
}
return null;
}
/**
* License
* @author zifangsky
* @date 2018/4/23 14:33
* @since 1.0.0
* @return demo.LicenseCheckModel
*/
private LicenseCheckModel getServerInfos(){
//操作系统类型
String osName = System.getProperty("os.name").toLowerCase();
AbstractServerInfos abstractServerInfos = null;
//根据不同操作系统类型选择不同的数据获取方法
if (osName.startsWith("windows")) {
abstractServerInfos = new WindowsServerInfos();
} else if (osName.startsWith("linux")) {
abstractServerInfos = new LinuxServerInfos();
}else{//其他服务器类型
abstractServerInfos = new LinuxServerInfos();
}
return abstractServerInfos.getServerInfos();
}
/**
* IP/MacIP<br/>
* IPIP/Mactrue
* @author zifangsky
* @date 2018/4/24 11:44
* @since 1.0.0
* @return boolean
*/
private boolean checkIpAddress(List<String> expectedList,List<String> serverList){
if(expectedList != null && expectedList.size() > 0){
if(serverList != null && serverList.size() > 0){
for(String expected : expectedList){
if(serverList.contains(expected.trim())){
return true;
}
}
}
return false;
}else {
return true;
}
}
/**
* CPU
* @author zifangsky
* @date 2018/4/24 14:38
* @since 1.0.0
* @param
* @return boolean
*/
private boolean checkSerial(String expectedSerial,String serverSerial){
if(StringUtils.isNotBlank(expectedSerial)){
if(StringUtils.isNotBlank(serverSerial)){
if(expectedSerial.equals(serverSerial)){
return true;
}
}
return false;
}else{
return true;
}
}
}

@ -0,0 +1,43 @@
package cn.zifangsky.license;
import com.alibaba.fastjson.JSON;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
/**
* LicenseCheckInterceptor
*
* @author zifangsky
* @date 2018/4/25
* @since 1.0.0
*/
public class LicenseCheckInterceptor extends HandlerInterceptorAdapter{
private static Logger logger = LogManager.getLogger(LicenseCheckInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
LicenseVerify licenseVerify = new LicenseVerify();
//校验证书是否有效
boolean verifyResult = licenseVerify.verify();
if(verifyResult){
return true;
}else{
response.setCharacterEncoding("utf-8");
Map<String,String> result = new HashMap<>(1);
result.put("result","您的证书无效,请核查服务器是否取得授权或重新申请证书!");
response.getWriter().write(JSON.toJSONString(result));
return false;
}
}
}

@ -0,0 +1,76 @@
package cn.zifangsky.license;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
/**
*
*
* @author zifangsky
* @date 2018/4/24
* @since 1.0.0
*/
@Component
public class LicenseCheckListener implements ApplicationListener<ContextRefreshedEvent> {
private static Logger logger = LogManager.getLogger(LicenseCheckListener.class);
/**
* subject
*/
@Value("${license.subject}")
private String subject;
/**
*
*/
@Value("${license.publicAlias}")
private String publicAlias;
/**
* 访
*/
@Value("${license.storePass}")
private String storePass;
/**
*
*/
@Value("${license.licensePath}")
private String licensePath;
/**
*
*/
@Value("${license.publicKeysStorePath}")
private String publicKeysStorePath;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
//root application context 没有parent
ApplicationContext context = event.getApplicationContext().getParent();
if(context == null){
if(StringUtils.isNotBlank(licensePath)){
logger.info("++++++++ 开始安装证书 ++++++++");
LicenseVerifyParam param = new LicenseVerifyParam();
param.setSubject(subject);
param.setPublicAlias(publicAlias);
param.setStorePass(storePass);
param.setLicensePath(licensePath);
param.setPublicKeysStorePath(publicKeysStorePath);
LicenseVerify licenseVerify = new LicenseVerify();
//安装证书
licenseVerify.install(param);
logger.info("++++++++ 证书安装结束 ++++++++");
}
}
}
}

@ -0,0 +1,77 @@
package cn.zifangsky.license;
import java.io.Serializable;
import java.util.List;
/**
* License
*
* @author zifangsky
* @date 2018/4/23
* @since 1.0.0
*/
public class LicenseCheckModel implements Serializable{
private static final long serialVersionUID = 8600137500316662317L;
/**
* IP
*/
private List<String> ipAddress;
/**
* MAC
*/
private List<String> macAddress;
/**
* CPU
*/
private String cpuSerial;
/**
*
*/
private String mainBoardSerial;
public List<String> getIpAddress() {
return ipAddress;
}
public void setIpAddress(List<String> ipAddress) {
this.ipAddress = ipAddress;
}
public List<String> getMacAddress() {
return macAddress;
}
public void setMacAddress(List<String> macAddress) {
this.macAddress = macAddress;
}
public String getCpuSerial() {
return cpuSerial;
}
public void setCpuSerial(String cpuSerial) {
this.cpuSerial = cpuSerial;
}
public String getMainBoardSerial() {
return mainBoardSerial;
}
public void setMainBoardSerial(String mainBoardSerial) {
this.mainBoardSerial = mainBoardSerial;
}
@Override
public String toString() {
return "LicenseCheckModel{" +
"ipAddress=" + ipAddress +
", macAddress=" + macAddress +
", cpuSerial='" + cpuSerial + '\'' +
", mainBoardSerial='" + mainBoardSerial + '\'' +
'}';
}
}

@ -0,0 +1,29 @@
package cn.zifangsky.license;
import de.schlichtherle.license.LicenseManager;
import de.schlichtherle.license.LicenseParam;
/**
* de.schlichtherle.license.LicenseManager
*
* @author zifangsky
* @date 2018/4/19
* @since 1.0.0
*/
public class LicenseManagerHolder {
private static volatile LicenseManager LICENSE_MANAGER;
public static LicenseManager getInstance(LicenseParam param){
if(LICENSE_MANAGER == null){
synchronized (LicenseManagerHolder.class){
if(LICENSE_MANAGER == null){
LICENSE_MANAGER = new CustomLicenseManager(param);
}
}
}
return LICENSE_MANAGER;
}
}

@ -0,0 +1,96 @@
package cn.zifangsky.license;
import de.schlichtherle.license.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.prefs.Preferences;
/**
* License
*
* @author zifangsky
* @date 2018/4/20
* @since 1.0.0
*/
public class LicenseVerify {
private static Logger logger = LogManager.getLogger(LicenseVerify.class);
/**
* License
* @author zifangsky
* @date 2018/4/20 16:26
* @since 1.0.0
*/
public synchronized LicenseContent install(LicenseVerifyParam param){
LicenseContent result = null;
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//1. 安装证书
try{
LicenseManager licenseManager = LicenseManagerHolder.getInstance(initLicenseParam(param));
licenseManager.uninstall();
result = licenseManager.install(new File(param.getLicensePath()));
logger.info(MessageFormat.format("证书安装成功,证书有效期:{0} - {1}",format.format(result.getNotBefore()),format.format(result.getNotAfter())));
}catch (Exception e){
logger.error("证书安装失败!",e);
}
return result;
}
/**
* License
* @author zifangsky
* @date 2018/4/20 16:26
* @since 1.0.0
* @return boolean
*/
public boolean verify(){
LicenseManager licenseManager = LicenseManagerHolder.getInstance(null);
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//2. 校验证书
try {
LicenseContent licenseContent = licenseManager.verify();
// System.out.println(licenseContent.getSubject());
logger.info(MessageFormat.format("证书校验通过,证书有效期:{0} - {1}",format.format(licenseContent.getNotBefore()),format.format(licenseContent.getNotAfter())));
return true;
}catch (Exception e){
logger.error("证书校验失败!",e);
return false;
}
}
/**
*
* @author zifangsky
* @date 2018/4/20 10:56
* @since 1.0.0
* @param param License
* @return de.schlichtherle.license.LicenseParam
*/
private LicenseParam initLicenseParam(LicenseVerifyParam param){
Preferences preferences = Preferences.userNodeForPackage(LicenseVerify.class);
CipherParam cipherParam = new DefaultCipherParam(param.getStorePass());
KeyStoreParam publicStoreParam = new CustomKeyStoreParam(LicenseVerify.class
,param.getPublicKeysStorePath()
,param.getPublicAlias()
,param.getStorePass()
,null);
return new DefaultLicenseParam(param.getSubject()
,preferences
,publicStoreParam
,cipherParam);
}
}

@ -0,0 +1,99 @@
package cn.zifangsky.license;
/**
* License
*
* @author zifangsky
* @date 2018/4/20
* @since 1.0.0
*/
public class LicenseVerifyParam {
/**
* subject
*/
private String subject;
/**
*
*/
private String publicAlias;
/**
* 访
*/
private String storePass;
/**
*
*/
private String licensePath;
/**
*
*/
private String publicKeysStorePath;
public LicenseVerifyParam() {
}
public LicenseVerifyParam(String subject, String publicAlias, String storePass, String licensePath, String publicKeysStorePath) {
this.subject = subject;
this.publicAlias = publicAlias;
this.storePass = storePass;
this.licensePath = licensePath;
this.publicKeysStorePath = publicKeysStorePath;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getPublicAlias() {
return publicAlias;
}
public void setPublicAlias(String publicAlias) {
this.publicAlias = publicAlias;
}
public String getStorePass() {
return storePass;
}
public void setStorePass(String storePass) {
this.storePass = storePass;
}
public String getLicensePath() {
return licensePath;
}
public void setLicensePath(String licensePath) {
this.licensePath = licensePath;
}
public String getPublicKeysStorePath() {
return publicKeysStorePath;
}
public void setPublicKeysStorePath(String publicKeysStorePath) {
this.publicKeysStorePath = publicKeysStorePath;
}
@Override
public String toString() {
return "LicenseVerifyParam{" +
"subject='" + subject + '\'' +
", publicAlias='" + publicAlias + '\'' +
", storePass='" + storePass + '\'' +
", licensePath='" + licensePath + '\'' +
", publicKeysStorePath='" + publicKeysStorePath + '\'' +
'}';
}
}

@ -0,0 +1,90 @@
package cn.zifangsky.license;
import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.util.List;
import java.util.stream.Collectors;
/**
* Linux
*
* @author zifangsky
* @date 2018/4/23
* @since 1.0.0
*/
public class LinuxServerInfos extends AbstractServerInfos{
@Override
protected List<String> getIpAddress() throws Exception {
List<String> result = null;
//获取所有网络接口
List<InetAddress> inetAddresses = getLocalAllInetAddress();
if(inetAddresses != null && inetAddresses.size() > 0){
result = inetAddresses.stream().map(InetAddress::getHostAddress).distinct().map(String::toLowerCase).collect(Collectors.toList());
}
return result;
}
@Override
protected List<String> getMacAddress() throws Exception {
List<String> result = null;
//1. 获取所有网络接口
List<InetAddress> inetAddresses = getLocalAllInetAddress();
if(inetAddresses != null && inetAddresses.size() > 0){
//2. 获取所有网络接口的Mac地址
result = inetAddresses.stream().map(this::getMacByInetAddress).distinct().collect(Collectors.toList());
}
return result;
}
@Override
protected String getCPUSerial() throws Exception {
//序列号
String serialNumber = "";
//使用dmidecode命令获取CPU序列号
String[] shell = {"/bin/bash","-c","dmidecode -t processor | grep 'ID' | awk -F ':' '{print $2}' | head -n 1"};
Process process = Runtime.getRuntime().exec(shell);
process.getOutputStream().close();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = reader.readLine().trim();
if(StringUtils.isNotBlank(line)){
serialNumber = line;
}
reader.close();
return serialNumber;
}
@Override
protected String getMainBoardSerial() throws Exception {
//序列号
String serialNumber = "";
//使用dmidecode命令获取主板序列号
String[] shell = {"/bin/bash","-c","dmidecode | grep 'Serial Number' | awk -F ':' '{print $2}' | head -n 1"};
Process process = Runtime.getRuntime().exec(shell);
process.getOutputStream().close();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = reader.readLine().trim();
if(StringUtils.isNotBlank(line)){
serialNumber = line;
}
reader.close();
return serialNumber;
}
}

@ -0,0 +1,89 @@
package cn.zifangsky.license;
import java.net.InetAddress;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;
/**
* Windows
*
* @author zifangsky
* @date 2018/4/23
* @since 1.0.0
*/
public class WindowsServerInfos extends AbstractServerInfos{
@Override
protected List<String> getIpAddress() throws Exception {
List<String> result = null;
//获取所有网络接口
List<InetAddress> inetAddresses = getLocalAllInetAddress();
if(inetAddresses != null && inetAddresses.size() > 0){
result = inetAddresses.stream().map(InetAddress::getHostAddress).distinct().map(String::toLowerCase).collect(Collectors.toList());
}
return result;
}
@Override
protected List<String> getMacAddress() throws Exception {
List<String> result = null;
//1. 获取所有网络接口
List<InetAddress> inetAddresses = getLocalAllInetAddress();
if(inetAddresses != null && inetAddresses.size() > 0){
//2. 获取所有网络接口的Mac地址
result = inetAddresses.stream().map(this::getMacByInetAddress).distinct().collect(Collectors.toList());
}
return result;
}
@Override
protected String getCPUSerial() throws Exception {
//序列号
String serialNumber = "";
//使用WMIC获取CPU序列号
Process process = Runtime.getRuntime().exec("wmic cpu get processorid");
process.getOutputStream().close();
Scanner scanner = new Scanner(process.getInputStream());
if(scanner != null && scanner.hasNext()){
scanner.next();
}
if(scanner.hasNext()){
serialNumber = scanner.next().trim();
}
scanner.close();
return serialNumber;
}
@Override
protected String getMainBoardSerial() throws Exception {
//序列号
String serialNumber = "";
//使用WMIC获取主板序列号
Process process = Runtime.getRuntime().exec("wmic baseboard get serialnumber");
process.getOutputStream().close();
Scanner scanner = new Scanner(process.getInputStream());
if(scanner != null && scanner.hasNext()){
scanner.next();
}
if(scanner.hasNext()){
serialNumber = scanner.next().trim();
}
scanner.close();
return serialNumber;
}
}

@ -0,0 +1,18 @@
server.port=7080
#session超时时间
server.servlet.session.timeout=300
#是否启用debug模式
#debug=true
logging.level.org.springframework.web=DEBUG
#logging.file=D:/runtime/test.log
#thymeleaf start
spring.thymeleaf.mode=LEGACYHTML5
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.template-resolver-order=0
spring.thymeleaf.cache=false
#thymeleaf end

@ -0,0 +1,2 @@
#使用哪个环境的配置
spring.profiles.active=dev

@ -0,0 +1,22 @@
${AnsiColor.BLUE}
_ooOoo_
o8888888o
88" . "88
(| ^_^ |)
O\ = /O
____/`---'\____
.' \\| | `.
/ \\||| : ||| \
/ _||||| -:- |||||- \
| | \\\ - / | |
| \_| ''\---/'' | |
\ .-\__ `-` ___/-. /
___`. .' /--.--\ `. . ___
."" '< `.___\_<|>_/___.' >'"".
| | : `- \`.;`\ _ /`;.`/ - ` : | |
\ \ `-. \_ __\ /__ _/ .-` / /
========`-.____`-.___\_____/___.-`____.-'========
`=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
佛祖保佑 永无BUG

@ -0,0 +1,6 @@
#License相关配置
license.subject=license_demo
license.publicAlias=publicCert
license.storePass=public_password1234
license.licensePath=C:/Users/zifangsky/Desktop/license_demo/license.lic
license.publicKeysStorePath=C:/Users/zifangsky/Desktop/license_demo/publicCerts.keystore

@ -0,0 +1,24 @@
body{
background: url("../img/3.jpg");
animation-name:myfirst;
animation-duration:20s;
/*变换时间*/
animation-delay:5s;
/*动画开始时间*/
animation-iteration-count:infinite;
/*下一周期循环播放*/
animation-play-state:running;
/*动画开始运行*/
}
@keyframes myfirst
{
0% {background:url("../img/3.jpg");}
34% {background:url("../img/2.jpg");}
67% {background:url("../img/1.jpg");}
100% {background:url("../img/3.jpg");}
}
.form{background: rgba(255,255,255,0.2);width:400px;margin:120px auto;}
/*阴影*/
.fa{display: inline-block;top: 27px;left: 6px;position: relative;color: #ccc;}
input[type="text"],input[type="password"]{padding-left:26px;}
.errMsg{color: red;}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

@ -0,0 +1,46 @@
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta content="text/html;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>首页</title>
<script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style>
body{
background: url("/img/4.jpg");
}
/*.container{
display:table;
height:100%;
}
.row{
display: table-cell;
vertical-align: middle;
}
.row-centered {
text-align:center;
}
.col-centered {
display:inline-block;
float:none;
text-align:left;
margin-right:-4px;
}*/
</style>
</head>
<body>
<!--<div class="container">
<div class="row clearfix">
<div class="col-md-12 column">
<h2 class="text-center">
欢迎访问首页
</h2>
</div>
</div>
</div>-->
</body>
</html>

@ -0,0 +1,93 @@
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta content="text/html;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>登录页面</title>
<
<script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" th:href="@{/css/style.css}"/>
<script>
//回车登录
function enterlogin(e) {
var key = window.event ? e.keyCode : e.which;
if (key === 13) {
userLogin();
}
}
//用户密码登录
function userLogin() {
//获取用户名、密码
var username = $("#username").val();
var password = $("#password").val();
if (username == null || username === "") {
$("#errMsg").text("请输入登陆用户名!");
$("#errMsg").attr("style", "display:block");
return;
}
if (password == null || password === "") {
$("#errMsg").text("请输入登陆密码!");
$("#errMsg").attr("style", "display:block");
return;
}
$.ajax({
url: "/check",
type: "POST",
dataType: "json",
async: false,
data: {
"username": username,
"password": password
},
success: function (data) {
if (data.code == "200") {
$("#errMsg").attr("style", "display:none");
window.location.href = '/userIndex';
} else if (data.result != null) {
$("#errMsg").text(data.result);
$("#errMsg").attr("style", "display:block");
} else {
$("#errMsg").text(data.msg);
$("#errMsg").attr("style", "display:block");
}
}
});
}
</script>
</head>
<body onkeydown="enterlogin(event);">
<div class="container">
<div class="form row">
<div class="form-horizontal col-md-offset-3" id="login_form">
<h3 class="form-title">LOGIN</h3>
<div class="col-md-9">
<div class="form-group">
<i class="fa fa-user fa-lg"></i>
<input class="form-control required" type="text" placeholder="Username" id="username"
name="username" autofocus="autofocus" maxlength="20"/>
</div>
<div class="form-group">
<i class="fa fa-lock fa-lg"></i>
<input class="form-control required" type="password" placeholder="Password" id="password"
name="password" maxlength="8"/>
</div>
<div class="form-group">
<span class="errMsg" id="errMsg" style="display: none">错误提示</span>
</div>
<div class="form-group col-md-offset-9">
<button type="submit" class="btn btn-success pull-right" name="submit" onclick="userLogin()">登录
</button>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

@ -0,0 +1,19 @@
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta content="text/html;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>用户首页</title>
<script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style>
body{
background: url("/img/5.jpg");
}
</style>
</head>
<body>
</body>
</html>

@ -0,0 +1,16 @@
package cn.zifangsky;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ClientDemoApplicationTests {
@Test
public void contextLoads() {
}
}

@ -1,37 +1,65 @@
# LicenseDemo
#### 项目介绍
有关基于Spring的项目中使用 TrueLicense 生成和验证License(服务器许可)的示例代码
在基于Spring的项目中使用 `TrueLicense `生成和验证`License证书`(服务器许可)的示例代码
#### 软件架构
软件架构说明
#### 技术依赖:
* `Spring Boot`:项目基础架构,包括提供`基本Web服务`和`定时调度服务`
* `TrueLicense `:基于`Java`实现的生成和验证服务器许可的简单框架
#### 环境依赖:
* `JDK8+`
#### 安装教程
#### 两个子项目说明: ####
1. xxxx
2. xxxx
3. xxxx
- `ServerDemo`:用于**开发者**给客户生成`License证书`的示例代码
- `ClientDemo`**模拟需要给客户部署的业务项目**
#### 使用说明
#### ServerDemo项目 ####
1. xxxx
2. xxxx
3. xxxx
对外发布了两个RESTful接口
#### 参与贡献
1获取服务器硬件信息
1. Fork 本项目
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
请求地址:`http://127.0.0.1:7000/license/getServerInfos`
![获取服务器硬件信息](https://www.zifangsky.cn/wp-content/uploads/2018/07/20180710140711.png)
#### 码云特技
2生成证书
请求地址:`http://127.0.0.1:7000/license/generateLicense`
请求时需要在Header中添加一个 **Content-Type** ,其值为:**application/json;charset=UTF-8**。请求参数如下:
```json
{
"subject": "license_demo",
"privateAlias": "privateKey",
"keyPass": "private_password1234",
"storePass": "public_password1234",
"licensePath": "C:/Users/zifangsky/Desktop/license_demo/license.lic",
"privateKeysStorePath": "C:/Users/zifangsky/Desktop/license_demo/privateKeys.keystore",
"issuedTime": "2018-07-10 00:00:01",
"expiryTime": "2019-12-31 23:59:59",
"consumerType": "User",
"consumerAmount": 1,
"description": "这是证书描述信息",
"licenseCheckModel": {
"ipAddress": ["192.168.245.1", "10.0.5.22"],
"macAddress": ["00-50-56-C0-00-01", "50-7B-9D-F9-18-41"],
"cpuSerial": "BFEBFBFF000406E3",
"mainBoardSerial": "L1HF65E00X9"
}
}
```
![生成证书](https://www.zifangsky.cn/wp-content/uploads/2018/07/20180710141528.png)
#### ClientDemo项目 ####
项目启动时安装证书,通过`cn/zifangsky/license/LicenseCheckListener.java`类实现。用户登录时校验证书的可用性,通过`cn/zifangsky/license/LicenseCheckInterceptor.java`类实现。
#### 特别说明: ####
详细开发思路可以参考我写的这篇文章:[https://www.zifangsky.cn/1277.html](https://www.zifangsky.cn/1277.html)
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目
5. 码云官方提供的使用手册 [http://git.mydoc.io/](http://git.mydoc.io/)
6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

@ -0,0 +1,25 @@
/target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

Binary file not shown.

@ -0,0 +1 @@
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip

225
ServerDemo/mvnw vendored

@ -0,0 +1,225 @@
#!/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
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
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() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
echo $MAVEN_PROJECTBASEDIR
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
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

143
ServerDemo/mvnw.cmd vendored

@ -0,0 +1,143 @@
@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
@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
%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%

@ -0,0 +1,165 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.zifangsky</groupId>
<artifactId>serverdemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ServerDemo</name>
<description>Demo project for License</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- 打包时忽略测试代码 -->
<skipTests>true</skipTests>
<!-- JUnit单元测试 -->
<junit>4.12</junit>
<!-- Apache Commons系列公共库 -->
<commons-lang3>3.7</commons-lang3>
<commons-io>2.6</commons-io>
<commons-codec>1.11</commons-codec>
<!-- Apache HttpClient -->
<httpclient>4.5.5</httpclient>
<!-- Fastjson -->
<fastjson>1.2.47</fastjson>
<!-- Java Servlet API -->
<javax.servlet-api>4.0.1</javax.servlet-api>
<!-- License -->
<truelicense>1.33</truelicense>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit}</version>
<scope>test</scope>
</dependency>
<!-- Commons -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec}</version>
</dependency>
<!-- Apache HttpClient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient}</version>
</dependency>
<!-- Fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson}</version>
</dependency>
<!-- Java Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${javax.servlet-api}</version>
<scope>provided</scope>
</dependency>
<!-- Jackson对自动解析JSON和XML格式的支持 -->
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<!-- SLF4J和LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<!-- License -->
<dependency>
<groupId>de.schlichtherle.truelicense</groupId>
<artifactId>truelicense-core</artifactId>
<version>${truelicense}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.tld</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>

@ -0,0 +1,16 @@
package cn.zifangsky;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.PropertySource;
@SpringBootApplication
@ServletComponentScan
@PropertySource({"license-config.properties"}) //加载额外的配置
public class ServerDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ServerDemoApplication.class, args);
}
}

@ -0,0 +1,72 @@
package cn.zifangsky.common;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* Spring
* @author zifangsky
*/
@Component
public class SpringContextUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
applicationContext = context;
}
/**
* ApplicationContext
* @return
*/
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
/**
* beanbean
* @param name
* @return
*/
public static Object getBeanByName(String name){
return applicationContext.getBean(name);
}
/**
* beanclass
* @param <T>
* @param c
* @return
*/
public static <T> T getBeanByClass(Class<T> c){
return applicationContext.getBean(c);
}
/**
* beanclass
* @param <T>
* @param c
* @return
*/
public static <T> Map<String, T> getBeansByClass(Class<T> c){
return applicationContext.getBeansOfType(c);
}
/**
* HttpServletRequest
* @return
*/
public static HttpServletRequest getRequest() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = attributes.getRequest();
return request;
}
}

@ -0,0 +1,94 @@
package cn.zifangsky.config;
import org.apache.http.Header;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Configuration
public class RestTemplateConfig {
/**
* RestTemplate
* @param factory ClientHttpRequestFactory
* @return RestTemplate
*/
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory){
return new RestTemplate(factory);
}
/**
* ClientHttpRequestFactory
* SimpleClientHttpRequestFactory使java.netHttp
* @return
*/
// @Bean
// public SimpleClientHttpRequestFactory simpleClientHttpRequestFactory(){
// SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
//
// requestFactory.setReadTimeout(5000);
// requestFactory.setConnectTimeout(5000);
//
// return requestFactory;
// }
/**
* ClientHttpRequestFactory使
* HttpComponentsClientHttpRequestFactory使HttpclientHttp
* @return HttpComponentsClientHttpRequestFactory
*/
@Bean
public HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory(){
//Httpclient连接池长连接保持30秒
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
//设置总连接数
connectionManager.setMaxTotal(1000);
//设置同路由的并发数
connectionManager.setDefaultMaxPerRoute(1000);
//设置header
List<Header> headers = new ArrayList<Header>();
headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04"));
headers.add(new BasicHeader("Accept-Encoding", "gzip, deflate"));
headers.add(new BasicHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"));
headers.add(new BasicHeader("Connection", "keep-alive"));
//创建HttpClient
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.setDefaultHeaders(headers)
.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) //设置重试次数
.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()) //设置保持长连接
.build();
//创建HttpComponentsClientHttpRequestFactory实例
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory(httpClient);
//设置客户端和服务端建立连接的超时时间
requestFactory.setConnectTimeout(5000);
//设置客户端从服务端读取数据的超时时间
requestFactory.setReadTimeout(5000);
//设置从连接池获取连接的超时时间,不宜过长
requestFactory.setConnectionRequestTimeout(200);
//缓冲请求数据默认为true。通过POST或者PUT大量发送数据时建议将此更改为false以免耗尽内存
requestFactory.setBufferRequestBody(false);
return requestFactory;
}
}

@ -0,0 +1,23 @@
package cn.zifangsky.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Web
* @author zifangsky
* @date 2018/7/9
* @since 1.0.0
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
*
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index").setViewName("index");
}
}

@ -0,0 +1,97 @@
package cn.zifangsky.controller;
import cn.zifangsky.license.LicenseCreator;
import cn.zifangsky.license.LinuxServerInfos;
import cn.zifangsky.license.AbstractServerInfos;
import cn.zifangsky.license.LicenseCheckModel;
import cn.zifangsky.license.LicenseCreatorParam;
import cn.zifangsky.license.WindowsServerInfos;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
*
*
* @author zifangsky
* @date 2018/4/26
* @since 1.0.0
*/
@RestController
@RequestMapping("/license")
public class LicenseCreatorController {
/**
*
*/
@Value("${license.licensePath}")
private String licensePath;
/**
*
* @author zifangsky
* @date 2018/4/26 13:13
* @since 1.0.0
* @param osName
* @return com.ccx.models.license.LicenseCheckModel
*/
@RequestMapping(value = "/getServerInfos",produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public LicenseCheckModel getServerInfos(@RequestParam(value = "osName",required = false) String osName) {
//操作系统类型
if(StringUtils.isBlank(osName)){
osName = System.getProperty("os.name");
}
osName = osName.toLowerCase();
AbstractServerInfos abstractServerInfos = null;
//根据不同操作系统类型选择不同的数据获取方法
if (osName.startsWith("windows")) {
abstractServerInfos = new WindowsServerInfos();
} else if (osName.startsWith("linux")) {
abstractServerInfos = new LinuxServerInfos();
}else{//其他服务器类型
abstractServerInfos = new LinuxServerInfos();
}
return abstractServerInfos.getServerInfos();
}
/**
*
* @author zifangsky
* @date 2018/4/26 13:13
* @since 1.0.0
* @param param {"subject":"ccx-models","privateAlias":"privateKey","keyPass":"5T7Zz5Y0dJFcqTxvzkH5LDGJJSGMzQ","storePass":"3538cef8e7","licensePath":"C:/Users/zifangsky/Desktop/license.lic","privateKeysStorePath":"C:/Users/zifangsky/Desktop/privateKeys.keystore","issuedTime":"2018-04-26 14:48:12","expiryTime":"2018-12-31 00:00:00","consumerType":"User","consumerAmount":1,"description":"这是证书描述信息","licenseCheckModel":{"ipAddress":["192.168.245.1","10.0.5.22"],"macAddress":["00-50-56-C0-00-01","50-7B-9D-F9-18-41"],"cpuSerial":"BFEBFBFF000406E3","mainBoardSerial":"L1HF65E00X9"}}
* @return java.util.Map<java.lang.String,java.lang.Object>
*/
@RequestMapping(value = "/generateLicense",produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public Map<String,Object> generateLicense(@RequestBody(required = true) LicenseCreatorParam param) {
Map<String,Object> resultMap = new HashMap<>(2);
if(StringUtils.isBlank(param.getLicensePath())){
param.setLicensePath(licensePath);
}
LicenseCreator licenseCreator = new LicenseCreator(param);
boolean result = licenseCreator.generateLicense();
if(result){
resultMap.put("result","ok");
resultMap.put("msg",param);
}else{
resultMap.put("result","error");
resultMap.put("msg","证书文件生成失败!");
}
return resultMap;
}
}

@ -0,0 +1,144 @@
package cn.zifangsky.license;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
/**
* IPMacCPU
*
* @author zifangsky
* @date 2018/4/23
* @since 1.0.0
*/
public abstract class AbstractServerInfos {
private static Logger logger = LogManager.getLogger(AbstractServerInfos.class);
/**
* License
* @author zifangsky
* @date 2018/4/23 14:23
* @since 1.0.0
* @return demo.LicenseCheckModel
*/
public LicenseCheckModel getServerInfos(){
LicenseCheckModel result = new LicenseCheckModel();
try {
result.setIpAddress(this.getIpAddress());
result.setMacAddress(this.getMacAddress());
result.setCpuSerial(this.getCPUSerial());
result.setMainBoardSerial(this.getMainBoardSerial());
}catch (Exception e){
logger.error("获取服务器硬件信息失败",e);
}
return result;
}
/**
* IP
* @author zifangsky
* @date 2018/4/23 11:32
* @since 1.0.0
* @return java.util.List<java.lang.String>
*/
protected abstract List<String> getIpAddress() throws Exception;
/**
* Mac
* @author zifangsky
* @date 2018/4/23 11:32
* @since 1.0.0
* @return java.util.List<java.lang.String>
*/
protected abstract List<String> getMacAddress() throws Exception;
/**
* CPU
* @author zifangsky
* @date 2018/4/23 11:35
* @since 1.0.0
* @return java.lang.String
*/
protected abstract String getCPUSerial() throws Exception;
/**
*
* @author zifangsky
* @date 2018/4/23 11:35
* @since 1.0.0
* @return java.lang.String
*/
protected abstract String getMainBoardSerial() throws Exception;
/**
* InetAddress
* @author zifangsky
* @date 2018/4/23 17:38
* @since 1.0.0
* @return java.util.List<java.net.InetAddress>
*/
protected List<InetAddress> getLocalAllInetAddress() throws Exception {
List<InetAddress> result = new ArrayList<>(4);
// 遍历所有的网络接口
for (Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); networkInterfaces.hasMoreElements(); ) {
NetworkInterface iface = (NetworkInterface) networkInterfaces.nextElement();
// 在所有的接口下再遍历IP
for (Enumeration inetAddresses = iface.getInetAddresses(); inetAddresses.hasMoreElements(); ) {
InetAddress inetAddr = (InetAddress) inetAddresses.nextElement();
//排除LoopbackAddress、SiteLocalAddress、LinkLocalAddress、MulticastAddress类型的IP地址
if(!inetAddr.isLoopbackAddress() /*&& !inetAddr.isSiteLocalAddress()*/
&& !inetAddr.isLinkLocalAddress() && !inetAddr.isMulticastAddress()){
result.add(inetAddr);
}
}
}
return result;
}
/**
* Mac
* @author zifangsky
* @date 2018/4/23 18:08
* @since 1.0.0
* @param
* @return void
*/
protected String getMacByInetAddress(InetAddress inetAddr){
try {
byte[] mac = NetworkInterface.getByInetAddress(inetAddr).getHardwareAddress();
StringBuffer stringBuffer = new StringBuffer();
for(int i=0;i<mac.length;i++){
if(i != 0) {
stringBuffer.append("-");
}
//将十六进制byte转化为字符串
String temp = Integer.toHexString(mac[i] & 0xff);
if(temp.length() == 1){
stringBuffer.append("0" + temp);
}else{
stringBuffer.append(temp);
}
}
return stringBuffer.toString().toUpperCase();
} catch (SocketException e) {
e.printStackTrace();
}
return null;
}
}

@ -0,0 +1,70 @@
package cn.zifangsky.license;
import de.schlichtherle.license.AbstractKeyStoreParam;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
* KeyStoreParam
*
* @author zifangsky
* @date 2018/4/26
* @since 1.0.0
*/
public class CustomKeyStoreParam extends AbstractKeyStoreParam {
/**
* /
*/
private String storePath;
private String alias;
private String storePwd;
private String keyPwd;
public CustomKeyStoreParam(Class clazz, String resource,String alias,String storePwd,String keyPwd) {
super(clazz, resource);
this.storePath = resource;
this.alias = alias;
this.storePwd = storePwd;
this.keyPwd = keyPwd;
}
@Override
public String getAlias() {
return alias;
}
@Override
public String getStorePwd() {
return storePwd;
}
@Override
public String getKeyPwd() {
return keyPwd;
}
/**
* de.schlichtherle.license.AbstractKeyStoreParamgetStream()<br/>
*
* @author zifangsky
* @date 2018/4/26 18:28
* @since 1.0.0
* @param
* @return java.io.InputStream
*/
@Override
public InputStream getStream() throws IOException {
final InputStream in = new FileInputStream(new File(storePath));
if (null == in){
throw new FileNotFoundException(storePath);
}
return in;
}
}

@ -0,0 +1,291 @@
package cn.zifangsky.license;
import de.schlichtherle.license.LicenseContent;
import de.schlichtherle.license.LicenseContentException;
import de.schlichtherle.license.LicenseManager;
import de.schlichtherle.license.LicenseNotary;
import de.schlichtherle.license.LicenseParam;
import de.schlichtherle.license.NoLicenseInstalledException;
import de.schlichtherle.xml.GenericCertificate;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;
/**
* LicenseManager
*
* @author zifangsky
* @date 2018/4/23
* @since 1.0.0
*/
public class CustomLicenseManager extends LicenseManager{
private static Logger logger = LogManager.getLogger(CustomLicenseManager.class);
//XML编码
private static final String XML_CHARSET = "UTF-8";
//默认BUFSIZE
private static final int DEFAULT_BUFSIZE = 8 * 1024;
public CustomLicenseManager() {
}
public CustomLicenseManager(LicenseParam param) {
super(param);
}
/**
* create
* @author zifangsky
* @date 2018/4/23 10:36
* @since 1.0.0
* @param
* @return byte[]
*/
@Override
protected synchronized byte[] create(
LicenseContent content,
LicenseNotary notary)
throws Exception {
initialize(content);
this.validateCreate(content);
final GenericCertificate certificate = notary.sign(content);
return getPrivacyGuard().cert2key(certificate);
}
/**
* installvalidatevalidateIPMac
* @author zifangsky
* @date 2018/4/23 10:40
* @since 1.0.0
* @param
* @return de.schlichtherle.license.LicenseContent
*/
@Override
protected synchronized LicenseContent install(
final byte[] key,
final LicenseNotary notary)
throws Exception {
final GenericCertificate certificate = getPrivacyGuard().key2cert(key);
notary.verify(certificate);
final LicenseContent content = (LicenseContent)this.load(certificate.getEncoded());
this.validate(content);
setLicenseKey(key);
setCertificate(certificate);
return content;
}
/**
* verifyvalidateIPMac
* @author zifangsky
* @date 2018/4/23 10:40
* @since 1.0.0
* @param
* @return de.schlichtherle.license.LicenseContent
*/
@Override
protected synchronized LicenseContent verify(final LicenseNotary notary)
throws Exception {
GenericCertificate certificate = getCertificate();
// Load license key from preferences,
final byte[] key = getLicenseKey();
if (null == key){
throw new NoLicenseInstalledException(getLicenseParam().getSubject());
}
certificate = getPrivacyGuard().key2cert(key);
notary.verify(certificate);
final LicenseContent content = (LicenseContent)this.load(certificate.getEncoded());
this.validate(content);
setCertificate(certificate);
return content;
}
/**
*
* @author zifangsky
* @date 2018/5/2 15:43
* @since 1.0.0
* @param content
*/
protected synchronized void validateCreate(final LicenseContent content)
throws LicenseContentException {
final LicenseParam param = getLicenseParam();
final Date now = new Date();
final Date notBefore = content.getNotBefore();
final Date notAfter = content.getNotAfter();
if (null != notAfter && now.after(notAfter)){
throw new LicenseContentException("证书失效时间不能早于当前时间");
}
if (null != notBefore && null != notAfter && notAfter.before(notBefore)){
throw new LicenseContentException("证书生效时间不能晚于证书失效时间");
}
final String consumerType = content.getConsumerType();
if (null == consumerType){
throw new LicenseContentException("用户类型不能为空");
}
}
/**
* validateIPMac
* @author zifangsky
* @date 2018/4/23 10:40
* @since 1.0.0
* @param content LicenseContent
*/
@Override
protected synchronized void validate(final LicenseContent content)
throws LicenseContentException {
//1. 首先调用父类的validate方法
super.validate(content);
//2. 然后校验自定义的License参数
//License中可被允许的参数信息
LicenseCheckModel expectedCheckModel = (LicenseCheckModel) content.getExtra();
//当前服务器真实的参数信息
LicenseCheckModel serverCheckModel = getServerInfos();
if(expectedCheckModel != null && serverCheckModel != null){
//校验IP地址
if(!checkIpAddress(expectedCheckModel.getIpAddress(),serverCheckModel.getIpAddress())){
throw new LicenseContentException("当前服务器的IP没在授权范围内");
}
//校验Mac地址
if(!checkIpAddress(expectedCheckModel.getMacAddress(),serverCheckModel.getMacAddress())){
throw new LicenseContentException("当前服务器的Mac地址没在授权范围内");
}
//校验主板序列号
if(!checkSerial(expectedCheckModel.getMainBoardSerial(),serverCheckModel.getMainBoardSerial())){
throw new LicenseContentException("当前服务器的主板序列号没在授权范围内");
}
//校验CPU序列号
if(!checkSerial(expectedCheckModel.getCpuSerial(),serverCheckModel.getCpuSerial())){
throw new LicenseContentException("当前服务器的CPU序列号没在授权范围内");
}
}else{
throw new LicenseContentException("不能获取服务器硬件信息");
}
}
/**
* XMLDecoderXML
* @author zifangsky
* @date 2018/4/25 14:02
* @since 1.0.0
* @param encoded XML
* @return java.lang.Object
*/
private Object load(String encoded){
BufferedInputStream inputStream = null;
XMLDecoder decoder = null;
try {
inputStream = new BufferedInputStream(new ByteArrayInputStream(encoded.getBytes(XML_CHARSET)));
decoder = new XMLDecoder(new BufferedInputStream(inputStream, DEFAULT_BUFSIZE),null,null);
return decoder.readObject();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} finally {
try {
if(decoder != null){
decoder.close();
}
if(inputStream != null){
inputStream.close();
}
} catch (Exception e) {
logger.error("XMLDecoder解析XML失败",e);
}
}
return null;
}
/**
* License
* @author zifangsky
* @date 2018/4/23 14:33
* @since 1.0.0
* @return demo.LicenseCheckModel
*/
private LicenseCheckModel getServerInfos(){
//操作系统类型
String osName = System.getProperty("os.name").toLowerCase();
AbstractServerInfos abstractServerInfos = null;
//根据不同操作系统类型选择不同的数据获取方法
if (osName.startsWith("windows")) {
abstractServerInfos = new WindowsServerInfos();
} else if (osName.startsWith("linux")) {
abstractServerInfos = new LinuxServerInfos();
}else{//其他服务器类型
abstractServerInfos = new LinuxServerInfos();
}
return abstractServerInfos.getServerInfos();
}
/**
* IP/MacIP<br/>
* IPIP/Mactrue
* @author zifangsky
* @date 2018/4/24 11:44
* @since 1.0.0
* @return boolean
*/
private boolean checkIpAddress(List<String> expectedList,List<String> serverList){
if(expectedList != null && expectedList.size() > 0){
if(serverList != null && serverList.size() > 0){
for(String expected : expectedList){
if(serverList.contains(expected.trim())){
return true;
}
}
}
return false;
}else {
return true;
}
}
/**
* CPU
* @author zifangsky
* @date 2018/4/24 14:38
* @since 1.0.0
* @return boolean
*/
private boolean checkSerial(String expectedSerial,String serverSerial){
if(StringUtils.isNotBlank(expectedSerial)){
if(StringUtils.isNotBlank(serverSerial)){
if(expectedSerial.equals(serverSerial)){
return true;
}
}
return false;
}else{
return true;
}
}
}

@ -0,0 +1,77 @@
package cn.zifangsky.license;
import java.io.Serializable;
import java.util.List;
/**
* License
*
* @author zifangsky
* @date 2018/4/23
* @since 1.0.0
*/
public class LicenseCheckModel implements Serializable{
private static final long serialVersionUID = 8600137500316662317L;
/**
* IP
*/
private List<String> ipAddress;
/**
* MAC
*/
private List<String> macAddress;
/**
* CPU
*/
private String cpuSerial;
/**
*
*/
private String mainBoardSerial;
public List<String> getIpAddress() {
return ipAddress;
}
public void setIpAddress(List<String> ipAddress) {
this.ipAddress = ipAddress;
}
public List<String> getMacAddress() {
return macAddress;
}
public void setMacAddress(List<String> macAddress) {
this.macAddress = macAddress;
}
public String getCpuSerial() {
return cpuSerial;
}
public void setCpuSerial(String cpuSerial) {
this.cpuSerial = cpuSerial;
}
public String getMainBoardSerial() {
return mainBoardSerial;
}
public void setMainBoardSerial(String mainBoardSerial) {
this.mainBoardSerial = mainBoardSerial;
}
@Override
public String toString() {
return "LicenseCheckModel{" +
"ipAddress=" + ipAddress +
", macAddress=" + macAddress +
", cpuSerial='" + cpuSerial + '\'' +
", mainBoardSerial='" + mainBoardSerial + '\'' +
'}';
}
}

@ -0,0 +1,108 @@
package cn.zifangsky.license;
import de.schlichtherle.license.CipherParam;
import de.schlichtherle.license.DefaultCipherParam;
import de.schlichtherle.license.DefaultLicenseParam;
import de.schlichtherle.license.KeyStoreParam;
import de.schlichtherle.license.LicenseContent;
import de.schlichtherle.license.LicenseManager;
import de.schlichtherle.license.LicenseParam;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.security.auth.x500.X500Principal;
import java.io.File;
import java.text.MessageFormat;
import java.util.prefs.Preferences;
/**
* License
*
* @author zifangsky
* @date 2018/4/19
* @since 1.0.0
*/
public class LicenseCreator {
private static Logger logger = LogManager.getLogger(LicenseCreator.class);
private final static X500Principal DEFAULT_HOLDER_AND_ISSUER = new X500Principal("CN=localhost, OU=localhost, O=localhost, L=SH, ST=SH, C=CN");
private LicenseCreatorParam param;
public LicenseCreator(LicenseCreatorParam param) {
this.param = param;
}
/**
* License
* @author zifangsky
* @date 2018/4/20 10:58
* @since 1.0.0
* @return boolean
*/
public boolean generateLicense(){
try {
LicenseManager licenseManager = new CustomLicenseManager(initLicenseParam());
LicenseContent licenseContent = initLicenseContent();
licenseManager.store(licenseContent,new File(param.getLicensePath()));
return true;
}catch (Exception e){
logger.error(MessageFormat.format("证书生成失败:{0}",param),e);
return false;
}
}
/**
*
* @author zifangsky
* @date 2018/4/20 10:56
* @since 1.0.0
* @return de.schlichtherle.license.LicenseParam
*/
private LicenseParam initLicenseParam(){
Preferences preferences = Preferences.userNodeForPackage(LicenseCreator.class);
//设置对证书内容加密的秘钥
CipherParam cipherParam = new DefaultCipherParam(param.getStorePass());
KeyStoreParam privateStoreParam = new CustomKeyStoreParam(LicenseCreator.class
,param.getPrivateKeysStorePath()
,param.getPrivateAlias()
,param.getStorePass()
,param.getKeyPass());
LicenseParam licenseParam = new DefaultLicenseParam(param.getSubject()
,preferences
,privateStoreParam
,cipherParam);
return licenseParam;
}
/**
*
* @author zifangsky
* @date 2018/4/20 10:57
* @since 1.0.0
* @return de.schlichtherle.license.LicenseContent
*/
private LicenseContent initLicenseContent(){
LicenseContent licenseContent = new LicenseContent();
licenseContent.setHolder(DEFAULT_HOLDER_AND_ISSUER);
licenseContent.setIssuer(DEFAULT_HOLDER_AND_ISSUER);
licenseContent.setSubject(param.getSubject());
licenseContent.setIssued(param.getIssuedTime());
licenseContent.setNotBefore(param.getIssuedTime());
licenseContent.setNotAfter(param.getExpiryTime());
licenseContent.setConsumerType(param.getConsumerType());
licenseContent.setConsumerAmount(param.getConsumerAmount());
licenseContent.setInfo(param.getDescription());
//扩展校验服务器硬件信息
licenseContent.setExtra(param.getLicenseCheckModel());
return licenseContent;
}
}

@ -0,0 +1,193 @@
package cn.zifangsky.license;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable;
import java.util.Date;
/**
* License
*
* @author zifangsky
* @date 2018/4/19
* @since 1.0.0
*/
public class LicenseCreatorParam implements Serializable {
private static final long serialVersionUID = -7793154252684580872L;
/**
* subject
*/
private String subject;
/**
*
*/
private String privateAlias;
/**
* 使
*/
private String keyPass;
/**
* 访
*/
private String storePass;
/**
*
*/
private String licensePath;
/**
*
*/
private String privateKeysStorePath;
/**
*
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date issuedTime = new Date();
/**
*
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date expiryTime;
/**
*
*/
private String consumerType = "user";
/**
*
*/
private Integer consumerAmount = 1;
/**
*
*/
private String description = "";
/**
*
*/
private LicenseCheckModel licenseCheckModel;
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getPrivateAlias() {
return privateAlias;
}
public void setPrivateAlias(String privateAlias) {
this.privateAlias = privateAlias;
}
public String getKeyPass() {
return keyPass;
}
public void setKeyPass(String keyPass) {
this.keyPass = keyPass;
}
public String getStorePass() {
return storePass;
}
public void setStorePass(String storePass) {
this.storePass = storePass;
}
public String getLicensePath() {
return licensePath;
}
public void setLicensePath(String licensePath) {
this.licensePath = licensePath;
}
public String getPrivateKeysStorePath() {
return privateKeysStorePath;
}
public void setPrivateKeysStorePath(String privateKeysStorePath) {
this.privateKeysStorePath = privateKeysStorePath;
}
public Date getIssuedTime() {
return issuedTime;
}
public void setIssuedTime(Date issuedTime) {
this.issuedTime = issuedTime;
}
public Date getExpiryTime() {
return expiryTime;
}
public void setExpiryTime(Date expiryTime) {
this.expiryTime = expiryTime;
}
public String getConsumerType() {
return consumerType;
}
public void setConsumerType(String consumerType) {
this.consumerType = consumerType;
}
public Integer getConsumerAmount() {
return consumerAmount;
}
public void setConsumerAmount(Integer consumerAmount) {
this.consumerAmount = consumerAmount;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public LicenseCheckModel getLicenseCheckModel() {
return licenseCheckModel;
}
public void setLicenseCheckModel(LicenseCheckModel licenseCheckModel) {
this.licenseCheckModel = licenseCheckModel;
}
@Override
public String toString() {
return "LicenseCreatorParam{" +
"subject='" + subject + '\'' +
", privateAlias='" + privateAlias + '\'' +
", keyPass='" + keyPass + '\'' +
", storePass='" + storePass + '\'' +
", licensePath='" + licensePath + '\'' +
", privateKeysStorePath='" + privateKeysStorePath + '\'' +
", issuedTime=" + issuedTime +
", expiryTime=" + expiryTime +
", consumerType='" + consumerType + '\'' +
", consumerAmount=" + consumerAmount +
", description='" + description + '\'' +
", licenseCheckModel=" + licenseCheckModel +
'}';
}
}

@ -0,0 +1,90 @@
package cn.zifangsky.license;
import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.util.List;
import java.util.stream.Collectors;
/**
* Linux
*
* @author zifangsky
* @date 2018/4/23
* @since 1.0.0
*/
public class LinuxServerInfos extends AbstractServerInfos {
@Override
protected List<String> getIpAddress() throws Exception {
List<String> result = null;
//获取所有网络接口
List<InetAddress> inetAddresses = getLocalAllInetAddress();
if(inetAddresses != null && inetAddresses.size() > 0){
result = inetAddresses.stream().map(InetAddress::getHostAddress).distinct().map(String::toLowerCase).collect(Collectors.toList());
}
return result;
}
@Override
protected List<String> getMacAddress() throws Exception {
List<String> result = null;
//1. 获取所有网络接口
List<InetAddress> inetAddresses = getLocalAllInetAddress();
if(inetAddresses != null && inetAddresses.size() > 0){
//2. 获取所有网络接口的Mac地址
result = inetAddresses.stream().map(this::getMacByInetAddress).distinct().collect(Collectors.toList());
}
return result;
}
@Override
protected String getCPUSerial() throws Exception {
//序列号
String serialNumber = "";
//使用dmidecode命令获取CPU序列号
String[] shell = {"/bin/bash","-c","dmidecode -t processor | grep 'ID' | awk -F ':' '{print $2}' | head -n 1"};
Process process = Runtime.getRuntime().exec(shell);
process.getOutputStream().close();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = reader.readLine().trim();
if(StringUtils.isNotBlank(line)){
serialNumber = line;
}
reader.close();
return serialNumber;
}
@Override
protected String getMainBoardSerial() throws Exception {
//序列号
String serialNumber = "";
//使用dmidecode命令获取主板序列号
String[] shell = {"/bin/bash","-c","dmidecode | grep 'Serial Number' | awk -F ':' '{print $2}' | head -n 1"};
Process process = Runtime.getRuntime().exec(shell);
process.getOutputStream().close();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = reader.readLine().trim();
if(StringUtils.isNotBlank(line)){
serialNumber = line;
}
reader.close();
return serialNumber;
}
}

@ -0,0 +1,89 @@
package cn.zifangsky.license;
import java.net.InetAddress;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;
/**
* Windows
*
* @author zifangsky
* @date 2018/4/23
* @since 1.0.0
*/
public class WindowsServerInfos extends AbstractServerInfos {
@Override
protected List<String> getIpAddress() throws Exception {
List<String> result = null;
//获取所有网络接口
List<InetAddress> inetAddresses = getLocalAllInetAddress();
if(inetAddresses != null && inetAddresses.size() > 0){
result = inetAddresses.stream().map(InetAddress::getHostAddress).distinct().map(String::toLowerCase).collect(Collectors.toList());
}
return result;
}
@Override
protected List<String> getMacAddress() throws Exception {
List<String> result = null;
//1. 获取所有网络接口
List<InetAddress> inetAddresses = getLocalAllInetAddress();
if(inetAddresses != null && inetAddresses.size() > 0){
//2. 获取所有网络接口的Mac地址
result = inetAddresses.stream().map(this::getMacByInetAddress).distinct().collect(Collectors.toList());
}
return result;
}
@Override
protected String getCPUSerial() throws Exception {
//序列号
String serialNumber = "";
//使用WMIC获取CPU序列号
Process process = Runtime.getRuntime().exec("wmic cpu get processorid");
process.getOutputStream().close();
Scanner scanner = new Scanner(process.getInputStream());
if(scanner.hasNext()){
scanner.next();
}
if(scanner.hasNext()){
serialNumber = scanner.next().trim();
}
scanner.close();
return serialNumber;
}
@Override
protected String getMainBoardSerial() throws Exception {
//序列号
String serialNumber = "";
//使用WMIC获取主板序列号
Process process = Runtime.getRuntime().exec("wmic baseboard get serialnumber");
process.getOutputStream().close();
Scanner scanner = new Scanner(process.getInputStream());
if(scanner.hasNext()){
scanner.next();
}
if(scanner.hasNext()){
serialNumber = scanner.next().trim();
}
scanner.close();
return serialNumber;
}
}

@ -0,0 +1,18 @@
server.port=7000
#session超时时间
server.servlet.session.timeout=300
#是否启用debug模式
#debug=true
logging.level.org.springframework.web=DEBUG
#logging.file=D:/runtime/test.log
#thymeleaf start
spring.thymeleaf.mode=LEGACYHTML5
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.template-resolver-order=0
spring.thymeleaf.cache=false
#thymeleaf end

@ -0,0 +1,2 @@
#使用哪个环境的配置
spring.profiles.active=dev

@ -0,0 +1,22 @@
${AnsiColor.BLUE}
_ooOoo_
o8888888o
88" . "88
(| ^_^ |)
O\ = /O
____/`---'\____
.' \\| | `.
/ \\||| : ||| \
/ _||||| -:- |||||- \
| | \\\ - / | |
| \_| ''\---/'' | |
\ .-\__ `-` ___/-. /
___`. .' /--.--\ `. . ___
."" '< `.___\_<|>_/___.' >'"".
| | : `- \`.;`\ _ /`;.`/ - ` : | |
\ \ `-. \_ __\ /__ _/ .-` / /
========`-.____`-.___\_____/___.-`____.-'========
`=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
佛祖保佑 永无BUG

@ -0,0 +1,2 @@
#License相关配置
license.licensePath=C:/Users/zifangsky/Desktop/license_demo/license.lic

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

@ -0,0 +1,46 @@
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta content="text/html;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>首页</title>
<script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style>
body{
background: url("/img/6.jpg");
}
/*.container{
display:table;
height:100%;
}
.row{
display: table-cell;
vertical-align: middle;
}
.row-centered {
text-align:center;
}
.col-centered {
display:inline-block;
float:none;
text-align:left;
margin-right:-4px;
}*/
</style>
</head>
<body>
<!--<div class="container">
<div class="row clearfix">
<div class="col-md-12 column">
<h2 class="text-center">
欢迎访问首页
</h2>
</div>
</div>
</div>-->
</body>
</html>

@ -0,0 +1,16 @@
package cn.zifangsky;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ServerDemoApplicationTests {
@Test
public void contextLoads() {
}
}
Loading…
Cancel
Save