diff --git a/README.md b/README.md index 5ef8b38..db31f5a 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Distributed Java.Let's [READ](SUMMARY.md)! 与本书配套的书籍已经出版: -* [《分布式系统常用技术及案例分析》](https://github.com/waylau/distributed-systems-technologies-and-cases-analysis) +* [《分布式系统开发实战》](https://github.com/waylau/distributed-system-tutorial-samples) ## 联系作者 diff --git a/samples/hello-world-docker/.gitignore b/samples/hello-world-docker/.gitignore new file mode 100644 index 0000000..4c6eb77 --- /dev/null +++ b/samples/hello-world-docker/.gitignore @@ -0,0 +1,26 @@ +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ +/bin/ diff --git a/samples/hello-world-docker/Dockerfile b/samples/hello-world-docker/Dockerfile new file mode 100644 index 0000000..1c2d5cb --- /dev/null +++ b/samples/hello-world-docker/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:8-jdk-alpine +VOLUME /tmp +ARG JAR_FILE +ADD ${JAR_FILE} app.jar +ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] \ No newline at end of file diff --git a/samples/hello-world-docker/build.gradle b/samples/hello-world-docker/build.gradle new file mode 100644 index 0000000..302871a --- /dev/null +++ b/samples/hello-world-docker/build.gradle @@ -0,0 +1,64 @@ +// buildscript 代码块中脚本优先执行 +buildscript { + + // ext 用于定义动态属性 + ext { + springBootVersion = '2.0.0.M4' + } + + // 使用了Maven的中央仓库及Spring自己的仓库(也可以指定其他仓库) + repositories { + //mavenCentral() + maven { url "https://repo.spring.io/snapshot" } + maven { url "https://repo.spring.io/milestone" } + maven { url "http://maven.aliyun.com/nexus/content/groups/public/" } + } + + // 依赖关系 + dependencies { + + // classpath 声明了在执行其余的脚本时,ClassLoader 可以使用这些依赖项 + classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") + + classpath('gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.17.2') + } +} + +// 使用插件 +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' + +apply plugin: 'com.palantir.docker' + +// 指定了生成的编译文件的版本,默认是打成了 jar 包 +group = 'com.waylau.spring.cloud' +version = '1.0.0' + +// 指定编译 .java 文件的 JDK 版本 +sourceCompatibility = 1.8 + +docker { + name "${project.group}/${jar.baseName}" + files jar.archivePath + buildArgs(['JAR_FILE': "${jar.archiveName}"]) +} + +// 使用了Maven的中央仓库及Spring自己的仓库(也可以指定其他仓库) +repositories { + //mavenCentral() + maven { url "https://repo.spring.io/snapshot" } + maven { url "https://repo.spring.io/milestone" } + maven { url "http://maven.aliyun.com/nexus/content/groups/public/" } +} + +// 依赖关系 +dependencies { + + // 该依赖用于编译阶段 + compile('org.springframework.boot:spring-boot-starter-web') + + // 该依赖用于测试阶段 + testCompile('org.springframework.boot:spring-boot-starter-test') +} diff --git a/samples/hello-world-docker/gradle/wrapper/gradle-wrapper.jar b/samples/hello-world-docker/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..8e4144d Binary files /dev/null and b/samples/hello-world-docker/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/hello-world-docker/gradle/wrapper/gradle-wrapper.properties b/samples/hello-world-docker/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..6f37a7e --- /dev/null +++ b/samples/hello-world-docker/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +#Fri Jul 28 13:37:07 BST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +#distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.2-bin.zip +distributionUrl=file\:/D:/software/webdev/java/gradle-4.0-all.zip \ No newline at end of file diff --git a/samples/hello-world-docker/gradlew b/samples/hello-world-docker/gradlew new file mode 100644 index 0000000..4453cce --- /dev/null +++ b/samples/hello-world-docker/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +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 +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +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 + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/samples/hello-world-docker/gradlew.bat b/samples/hello-world-docker/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/samples/hello-world-docker/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/samples/hello-world-docker/src/main/java/com/waylau/spring/cloud/weather/Application.java b/samples/hello-world-docker/src/main/java/com/waylau/spring/cloud/weather/Application.java new file mode 100644 index 0000000..ba49587 --- /dev/null +++ b/samples/hello-world-docker/src/main/java/com/waylau/spring/cloud/weather/Application.java @@ -0,0 +1,18 @@ +package com.waylau.spring.cloud.weather; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * 主应用程序. + * + * @since 1.0.0 2017年9月27日 + * @author Way Lau + */ +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/samples/hello-world-docker/src/main/java/com/waylau/spring/cloud/weather/controller/HelloController.java b/samples/hello-world-docker/src/main/java/com/waylau/spring/cloud/weather/controller/HelloController.java new file mode 100644 index 0000000..3a9dfd1 --- /dev/null +++ b/samples/hello-world-docker/src/main/java/com/waylau/spring/cloud/weather/controller/HelloController.java @@ -0,0 +1,20 @@ +package com.waylau.spring.cloud.weather.controller; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Hello Controller. + * + * @since 1.0.0 2017年9月27日 + * @author Way Lau + */ +@RestController +public class HelloController { + + @RequestMapping("/hello") + public String hello() { + return "Hello World! Welcome to visit waylau.com!"; + } + +} diff --git a/samples/hello-world-docker/src/main/resources/application.properties b/samples/hello-world-docker/src/main/resources/application.properties new file mode 100644 index 0000000..e69de29 diff --git a/samples/hello-world-docker/src/test/java/com/waylau/spring/cloud/weather/ApplicationTests.java b/samples/hello-world-docker/src/test/java/com/waylau/spring/cloud/weather/ApplicationTests.java new file mode 100644 index 0000000..71072b0 --- /dev/null +++ b/samples/hello-world-docker/src/test/java/com/waylau/spring/cloud/weather/ApplicationTests.java @@ -0,0 +1,22 @@ +package com.waylau.spring.cloud.weather; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * 主应用测试用例. + * + * @since 1.0.0 2017年9月27日 + * @author Way Lau + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class ApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/samples/hello-world-docker/src/test/java/com/waylau/spring/cloud/weather/controller/HelloControllerTest.java b/samples/hello-world-docker/src/test/java/com/waylau/spring/cloud/weather/controller/HelloControllerTest.java new file mode 100644 index 0000000..0dd9e77 --- /dev/null +++ b/samples/hello-world-docker/src/test/java/com/waylau/spring/cloud/weather/controller/HelloControllerTest.java @@ -0,0 +1,36 @@ +package com.waylau.spring.cloud.weather.controller; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import static org.hamcrest.Matchers.equalTo; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * HelloController Test. + * + * @since 1.0.0 2017年9月27日 + * @author Way Lau + */ +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +public class HelloControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void testHello() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().string(equalTo("Hello World! Welcome to visit waylau.com!"))); + } +} \ No newline at end of file diff --git a/samples/security-basic/.gitignore b/samples/security-basic/.gitignore new file mode 100644 index 0000000..fd6098f --- /dev/null +++ b/samples/security-basic/.gitignore @@ -0,0 +1,27 @@ +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ +/bin/ +/target/ diff --git a/samples/security-basic/dependency-reduced-pom.xml b/samples/security-basic/dependency-reduced-pom.xml new file mode 100644 index 0000000..47d9e53 --- /dev/null +++ b/samples/security-basic/dependency-reduced-pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + com.waylau.spring + security-basic + security-basic + 1.0.0 + + waylau.com + https://waylau.com + + + + + maven-shade-plugin + 3.6.0 + + + package + + shade + + + + + com.waylau.spring.mvc.Application + + + + + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + + + 5.2.15.RELEASE + 5.1.5.RELEASE + 9.4.14.v20181114 + 2.9.7 + + diff --git a/samples/security-basic/pom.xml b/samples/security-basic/pom.xml new file mode 100644 index 0000000..f887935 --- /dev/null +++ b/samples/security-basic/pom.xml @@ -0,0 +1,92 @@ + + 4.0.0 + com.waylau.spring + security-basic + 1.0.0 + security-basic + jar + + waylau.com + https://waylau.com + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + + + + 5.1.5.RELEASE + 9.4.14.v20181114 + 2.9.7 + 5.2.15.RELEASE + + + + + org.springframework + spring-webmvc + ${spring.version} + + + org.eclipse.jetty + jetty-servlet + ${jetty.version} + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + + org.springframework.security + spring-security-web + ${spring-security.version} + + + org.springframework.security + spring-security-config + ${spring-security.version} + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + + package + + shade + + + + + com.waylau.spring.mvc.Application + + + + + + + + + + \ No newline at end of file diff --git a/samples/security-basic/src/main/java/com/waylau/spring/mvc/Application.java b/samples/security-basic/src/main/java/com/waylau/spring/mvc/Application.java new file mode 100644 index 0000000..c50bcec --- /dev/null +++ b/samples/security-basic/src/main/java/com/waylau/spring/mvc/Application.java @@ -0,0 +1,18 @@ +/** + * Welcome to https://waylau.com + */ +package com.waylau.spring.mvc; + +/** + * Application Main. + * + * @since 1.0.0 2018年3月21日 + * @author Way Lau + */ +public class Application { + + public static void main(String[] args) throws Exception { + new JettyServer().run(); + } + +} diff --git a/samples/security-basic/src/main/java/com/waylau/spring/mvc/JettyServer.java b/samples/security-basic/src/main/java/com/waylau/spring/mvc/JettyServer.java new file mode 100644 index 0000000..889c40c --- /dev/null +++ b/samples/security-basic/src/main/java/com/waylau/spring/mvc/JettyServer.java @@ -0,0 +1,59 @@ +package com.waylau.spring.mvc; + +import java.util.EnumSet; +import javax.servlet.DispatcherType; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.springframework.web.context.ContextLoaderListener; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.web.filter.DelegatingFilterProxy; +import org.springframework.web.servlet.DispatcherServlet; +import com.waylau.spring.mvc.configuration.AppConfiguration; + +/** + * Jetty Server. + * + * @since 1.0.0 2018年3月21日 + * @author Way Lau + */ +public class JettyServer { + private static final int DEFAULT_PORT = 8080; + private static final String CONTEXT_PATH = "/"; + private static final String MAPPING_URL = "/*"; + + public void run() throws Exception { + Server server = new Server(DEFAULT_PORT); + server.setHandler(servletContextHandler(webApplicationContext())); + server.start(); + server.join(); + } + + private ServletContextHandler servletContextHandler(WebApplicationContext ct) { + // 启用Session管理器 + ServletContextHandler handler = + new ServletContextHandler(ServletContextHandler.SESSIONS); + + handler.setContextPath(CONTEXT_PATH); + handler.addServlet(new ServletHolder(new DispatcherServlet(ct)), + MAPPING_URL); + handler.addEventListener(new ContextLoaderListener(ct)); + + // 添加Spring Security过滤器 + FilterHolder filterHolder=new FilterHolder(DelegatingFilterProxy.class); + filterHolder.setName("springSecurityFilterChain"); + handler.addFilter(filterHolder, MAPPING_URL, + EnumSet.of(DispatcherType.REQUEST)); + + return handler; + } + + private WebApplicationContext webApplicationContext() { + AnnotationConfigWebApplicationContext context = + new AnnotationConfigWebApplicationContext(); + context.register(AppConfiguration.class); + return context; + } +} \ No newline at end of file diff --git a/samples/security-basic/src/main/java/com/waylau/spring/mvc/configuration/AppConfiguration.java b/samples/security-basic/src/main/java/com/waylau/spring/mvc/configuration/AppConfiguration.java new file mode 100644 index 0000000..7166073 --- /dev/null +++ b/samples/security-basic/src/main/java/com/waylau/spring/mvc/configuration/AppConfiguration.java @@ -0,0 +1,18 @@ +package com.waylau.spring.mvc.configuration; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * App Configuration. + * + * @since 1.0.0 2018年3月21日 + * @author Way Lau + */ +@Configuration +@ComponentScan(basePackages = { "com.waylau.spring" }) +@Import({ WebSecurityConfig.class, MvcConfiguration.class }) +public class AppConfiguration { + +} diff --git a/samples/security-basic/src/main/java/com/waylau/spring/mvc/configuration/MvcConfiguration.java b/samples/security-basic/src/main/java/com/waylau/spring/mvc/configuration/MvcConfiguration.java new file mode 100644 index 0000000..e0d5290 --- /dev/null +++ b/samples/security-basic/src/main/java/com/waylau/spring/mvc/configuration/MvcConfiguration.java @@ -0,0 +1,25 @@ +package com.waylau.spring.mvc.configuration; + +import java.util.List; + +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * MVC Configuration. + * + * @since 1.0.0 2018年3月21日 + * @author Way Lau + */ +@EnableWebMvc +@Configuration +public class MvcConfiguration implements WebMvcConfigurer { + + @Override + public void extendMessageConverters(List> converters) { + converters.add(new MappingJackson2HttpMessageConverter()); + } +} diff --git a/samples/security-basic/src/main/java/com/waylau/spring/mvc/configuration/WebSecurityConfig.java b/samples/security-basic/src/main/java/com/waylau/spring/mvc/configuration/WebSecurityConfig.java new file mode 100644 index 0000000..61fe249 --- /dev/null +++ b/samples/security-basic/src/main/java/com/waylau/spring/mvc/configuration/WebSecurityConfig.java @@ -0,0 +1,49 @@ +package com.waylau.spring.mvc.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; + +/** + * Web Security Configuration. + * + * @since 1.0.0 2018年3月21日 + * @author Way Lau + */ +@EnableWebSecurity // 启用Spring Security功能 +public class WebSecurityConfig + extends WebSecurityConfigurerAdapter { + + /** + * 自定义配置 + */ + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests().anyRequest().authenticated()//所有请求都需认证 + .and() + .formLogin() // 使用form表单登录 + .and() + .httpBasic(); // HTTP基本认证 + } + + @SuppressWarnings("deprecation") + @Bean + @Override + public UserDetailsService userDetailsService() { + InMemoryUserDetailsManager manager = + new InMemoryUserDetailsManager(); + + manager.createUser( + User.withDefaultPasswordEncoder() // 密码编码器 + .username("waylau") // 用户名 + .password("123") // 密码 + .roles("USER") // 角色 + .build() + ); + return manager; + } +} \ No newline at end of file diff --git a/samples/security-basic/src/main/java/com/waylau/spring/mvc/controller/HelloController.java b/samples/security-basic/src/main/java/com/waylau/spring/mvc/controller/HelloController.java new file mode 100644 index 0000000..9d7cab7 --- /dev/null +++ b/samples/security-basic/src/main/java/com/waylau/spring/mvc/controller/HelloController.java @@ -0,0 +1,27 @@ +package com.waylau.spring.mvc.controller; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.waylau.spring.mvc.vo.User; + + +/** + * Hello 控制器. + * + * @since 1.0.0 2018年3月21日 + * @author Way Lau + */ +@RestController +public class HelloController { + + @RequestMapping("/hello") + public String hello() { + return "Hello World! Welcome to visit waylau.com!"; + } + + @RequestMapping("/hello/way") + public User helloWay() { + return new User("Way Lau", 30); + } +} diff --git a/samples/security-basic/src/main/java/com/waylau/spring/mvc/vo/User.java b/samples/security-basic/src/main/java/com/waylau/spring/mvc/vo/User.java new file mode 100644 index 0000000..208153b --- /dev/null +++ b/samples/security-basic/src/main/java/com/waylau/spring/mvc/vo/User.java @@ -0,0 +1,37 @@ +/** + * Welcome to https://waylau.com + */ +package com.waylau.spring.mvc.vo; + +/** + * User. + * + * @since 1.0.0 2018年2月10日 + * @author Way Lau + */ +public class User { + private String username; + private Integer age; + + public User(String username, Integer age) { + this.username = username; + this.age = age; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + +} diff --git a/samples/spring-boot-rest/.gitignore b/samples/spring-boot-rest/.gitignore new file mode 100644 index 0000000..4c6eb77 --- /dev/null +++ b/samples/spring-boot-rest/.gitignore @@ -0,0 +1,26 @@ +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ +/bin/ diff --git a/samples/spring-boot-rest/build.gradle b/samples/spring-boot-rest/build.gradle new file mode 100644 index 0000000..bfa75dd --- /dev/null +++ b/samples/spring-boot-rest/build.gradle @@ -0,0 +1,54 @@ +// buildscript нűִ +buildscript { + + // ext ڶ嶯̬ + ext { + springBootVersion = '2.0.0.M4' + } + + // ʹMavenֿ⼰SpringԼIJֿ⣨Ҳָֿ⣩ + repositories { + //mavenCentral() + maven { url "https://repo.spring.io/snapshot" } + maven { url "https://repo.spring.io/milestone" } + maven { url "http://maven.aliyun.com/nexus/content/groups/public/" } + } + + // ϵ + dependencies { + + // classpath ִĽűʱClassLoader ʹЩ + classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") + } +} + +// ʹò +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' + +// ָɵıļİ汾ĬǴ jar +group = 'com.waylau.spring.cloud' +version = '1.0.0' + +// ָ .java ļ JDK 汾 +sourceCompatibility = 1.8 + +// ʹMavenֿ⼰SpringԼIJֿ⣨Ҳָֿ⣩ +repositories { + //mavenCentral() + maven { url "https://repo.spring.io/snapshot" } + maven { url "https://repo.spring.io/milestone" } + maven { url "http://maven.aliyun.com/nexus/content/groups/public/" } +} + +// ϵ +dependencies { + + // ڱ׶ + compile('org.springframework.boot:spring-boot-starter-web') + + // ڲԽ׶ + testCompile('org.springframework.boot:spring-boot-starter-test') +} diff --git a/samples/spring-boot-rest/gradle/wrapper/gradle-wrapper.jar b/samples/spring-boot-rest/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..8e4144d Binary files /dev/null and b/samples/spring-boot-rest/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/spring-boot-rest/gradle/wrapper/gradle-wrapper.properties b/samples/spring-boot-rest/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..6f37a7e --- /dev/null +++ b/samples/spring-boot-rest/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +#Fri Jul 28 13:37:07 BST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +#distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.2-bin.zip +distributionUrl=file\:/D:/software/webdev/java/gradle-4.0-all.zip \ No newline at end of file diff --git a/samples/spring-boot-rest/gradlew b/samples/spring-boot-rest/gradlew new file mode 100644 index 0000000..4453cce --- /dev/null +++ b/samples/spring-boot-rest/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +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 +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +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 + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/samples/spring-boot-rest/gradlew.bat b/samples/spring-boot-rest/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/samples/spring-boot-rest/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/Application.java b/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/Application.java new file mode 100644 index 0000000..ba49587 --- /dev/null +++ b/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/Application.java @@ -0,0 +1,18 @@ +package com.waylau.spring.cloud.weather; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * 主应用程序. + * + * @since 1.0.0 2017年9月27日 + * @author Way Lau + */ +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/controller/HelloController.java b/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/controller/HelloController.java new file mode 100644 index 0000000..3a9dfd1 --- /dev/null +++ b/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/controller/HelloController.java @@ -0,0 +1,20 @@ +package com.waylau.spring.cloud.weather.controller; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Hello Controller. + * + * @since 1.0.0 2017年9月27日 + * @author Way Lau + */ +@RestController +public class HelloController { + + @RequestMapping("/hello") + public String hello() { + return "Hello World! Welcome to visit waylau.com!"; + } + +} diff --git a/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/controller/UserController.java b/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/controller/UserController.java new file mode 100644 index 0000000..6235e20 --- /dev/null +++ b/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/controller/UserController.java @@ -0,0 +1,89 @@ +package com.waylau.spring.cloud.weather.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.waylau.spring.cloud.weather.domain.User; +import com.waylau.spring.cloud.weather.repository.UserRepository; + +/** + * User Controller. + * + * @author Way Lau + * @date 2017年10月8日 + */ +@RestController +@RequestMapping("/users") +public class UserController { + + @Autowired + private UserRepository userRepository; + + /** + * 获取用户列表 + * + * @return + */ + @GetMapping + public List getUsers() { + return userRepository.listUser(); + } + + /** + * 获取用户信息 + * + * @param id + * @return + */ + @GetMapping("/{id}") + public User getUser(@PathVariable("id") Long id) { + return userRepository.getUserById(id); + } + + /** + * 保存用户 + * + * @param user + */ + @PostMapping + public User createUser(@RequestBody User user) { + return userRepository.saveOrUpateUser(user); + } + + /** + * 修改用户 + * + * @param id + * @param user + */ + @PutMapping("/{id}") + public void updateUser(@PathVariable("id") Long id, @RequestBody User user) { + User oldUser = this.getUser(id); + + if (oldUser != null) { + user.setId(id); + userRepository.saveOrUpateUser(user); + } + + } + + /** + * 删除用户 + * + * @param id + * @return + */ + @DeleteMapping("/{id}") + public void deleteUser(@PathVariable("id") Long id) { + userRepository.deleteUser(id); + } +} diff --git a/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/domain/User.java b/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/domain/User.java new file mode 100644 index 0000000..5c05e9c --- /dev/null +++ b/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/domain/User.java @@ -0,0 +1,53 @@ +package com.waylau.spring.cloud.weather.domain; + +/** + * User. + * + * @since 1.0.0 2017年10月8日 + * @author Way Lau + */ +public class User { + + private Long id; + + private String name; + + private String email; + + public User() { + } + + public User(String name, String email) { + this.name = name; + this.email = email; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + @Override + public String toString() { + return String.format("User[id=%d, name='%s', email='%s']", id, name, email); + } +} diff --git a/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/repository/UserRepository.java b/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/repository/UserRepository.java new file mode 100644 index 0000000..937f51f --- /dev/null +++ b/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/repository/UserRepository.java @@ -0,0 +1,44 @@ +package com.waylau.spring.cloud.weather.repository; + +import java.util.List; + +import com.waylau.spring.cloud.weather.domain.User; + +/** + * 用户仓库. + * + * @since 1.0.0 2017年10月8日 + * @author Way Lau + */ +public interface UserRepository { + + /** + * 新增或者修改用户 + * + * @param user + * @return + */ + User saveOrUpateUser(User user); + + /** + * 删除用户 + * + * @param id + */ + void deleteUser(Long id); + + /** + * 根据用户id获取用户 + * + * @param id + * @return + */ + User getUserById(Long id); + + /** + * 获取所有用户的列表 + * + * @return + */ + List listUser(); +} diff --git a/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/repository/UserRepositoryImpl.java b/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/repository/UserRepositoryImpl.java new file mode 100644 index 0000000..be59679 --- /dev/null +++ b/samples/spring-boot-rest/src/main/java/com/waylau/spring/cloud/weather/repository/UserRepositoryImpl.java @@ -0,0 +1,52 @@ +package com.waylau.spring.cloud.weather.repository; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; + +import org.springframework.stereotype.Repository; + +import com.waylau.spring.cloud.weather.domain.User; + +/** + * 用户资源库. + * + * @version 1.0.0 2017年10月8日 + * @author Way Lau + */ +@Repository +public class UserRepositoryImpl implements UserRepository { + + private static AtomicLong counter = new AtomicLong(); + + private final ConcurrentMap userMap = new ConcurrentHashMap(); + + @Override + public User saveOrUpateUser(User user) { + Long id = user.getId(); + if (id == null || id <= 0) { + id = counter.incrementAndGet(); + user.setId(id); + } + this.userMap.put(id, user); + return this.getUserById(id); + } + + @Override + public void deleteUser(Long id) { + this.userMap.remove(id); + } + + @Override + public User getUserById(Long id) { + return this.userMap.get(id); + } + + @Override + public List listUser() { + return new ArrayList(this.userMap.values()); + } + +} diff --git a/samples/spring-boot-rest/src/main/resources/application.properties b/samples/spring-boot-rest/src/main/resources/application.properties new file mode 100644 index 0000000..e69de29 diff --git a/samples/spring-boot-rest/src/test/java/com/waylau/spring/cloud/weather/ApplicationTests.java b/samples/spring-boot-rest/src/test/java/com/waylau/spring/cloud/weather/ApplicationTests.java new file mode 100644 index 0000000..71072b0 --- /dev/null +++ b/samples/spring-boot-rest/src/test/java/com/waylau/spring/cloud/weather/ApplicationTests.java @@ -0,0 +1,22 @@ +package com.waylau.spring.cloud.weather; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * 主应用测试用例. + * + * @since 1.0.0 2017年9月27日 + * @author Way Lau + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class ApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/samples/spring-boot-rest/src/test/java/com/waylau/spring/cloud/weather/controller/HelloControllerTest.java b/samples/spring-boot-rest/src/test/java/com/waylau/spring/cloud/weather/controller/HelloControllerTest.java new file mode 100644 index 0000000..0dd9e77 --- /dev/null +++ b/samples/spring-boot-rest/src/test/java/com/waylau/spring/cloud/weather/controller/HelloControllerTest.java @@ -0,0 +1,36 @@ +package com.waylau.spring.cloud.weather.controller; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import static org.hamcrest.Matchers.equalTo; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * HelloController Test. + * + * @since 1.0.0 2017年9月27日 + * @author Way Lau + */ +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +public class HelloControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void testHello() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().string(equalTo("Hello World! Welcome to visit waylau.com!"))); + } +} \ No newline at end of file