Browse Source

init project

PLF 5 years ago
parent
commit
3b7f5024c3
34 changed files with 2151 additions and 10 deletions
  1. 27 10
      .gitignore
  2. 118 0
      .mvn/wrapper/MavenWrapperDownloader.java
  3. BIN
      .mvn/wrapper/maven-wrapper.jar
  4. 2 0
      .mvn/wrapper/maven-wrapper.properties
  5. 83 0
      catalina.out
  6. 310 0
      mvnw
  7. 182 0
      mvnw.cmd
  8. 166 0
      pom.xml
  9. 13 0
      src/main/java/com/caimei/CaimeiMallAdminApplication.java
  10. 125 0
      src/main/java/com/caimei/modules/shiro/auth/AuthFilter.java
  11. 69 0
      src/main/java/com/caimei/modules/shiro/auth/AuthRealm.java
  12. 22 0
      src/main/java/com/caimei/modules/shiro/auth/AuthToken.java
  13. 62 0
      src/main/java/com/caimei/modules/shiro/auth/ShiroConfig.java
  14. 38 0
      src/main/java/com/caimei/modules/shiro/auth/TokenGenerator.java
  15. 53 0
      src/main/java/com/caimei/modules/shiro/controller/ShiroController.java
  16. 12 0
      src/main/java/com/caimei/modules/shiro/dao/SysTokenRepository.java
  17. 13 0
      src/main/java/com/caimei/modules/shiro/dao/UserMapper.java
  18. 70 0
      src/main/java/com/caimei/modules/shiro/entity/CmMallAdminUser.java
  19. 33 0
      src/main/java/com/caimei/modules/shiro/entity/Permission.java
  20. 35 0
      src/main/java/com/caimei/modules/shiro/entity/Role.java
  21. 60 0
      src/main/java/com/caimei/modules/shiro/entity/SysToken.java
  22. 13 0
      src/main/java/com/caimei/modules/shiro/service/ShiroService.java
  23. 45 0
      src/main/java/com/caimei/modules/shiro/service/impl/ShiroServiceImpl.java
  24. 23 0
      src/main/java/com/caimei/utils/HttpContextUtils.java
  25. 113 0
      src/main/java/com/caimei/utils/JsonModel.java
  26. 82 0
      src/main/java/com/caimei/utils/MD5Util.java
  27. 94 0
      src/main/java/com/caimei/utils/TokenEncryptUtils.java
  28. 3 0
      src/main/resources/application.yml
  29. 42 0
      src/main/resources/dev/application-dev.yml
  30. 26 0
      src/main/resources/mapper/UserMapper.xml
  31. 43 0
      src/main/resources/prod/application-prod.yml
  32. 19 0
      src/main/resources/public/index.html
  33. 42 0
      src/main/resources/test/application-test.yml
  34. 113 0
      src/test/java/com/caimei/TokenUtils.java

+ 27 - 10
.gitignore

@@ -1,14 +1,31 @@
-# ---> Java
-*.class
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**
+!**/src/test/**
 
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
 
-# Package Files #
-*.jar
-*.war
-*.ear
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
 
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
 
+### VS Code ###
+.vscode/

+ 118 - 0
.mvn/wrapper/MavenWrapperDownloader.java

@@ -0,0 +1,118 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed 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
+ *
+ *      https://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.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+    private static final String WRAPPER_VERSION = "0.5.5";
+    /**
+     * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+     */
+    private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+            + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+    /**
+     * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+     * use instead of the default one.
+     */
+    private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+            ".mvn/wrapper/maven-wrapper.properties";
+
+    /**
+     * Path where the maven-wrapper.jar will be saved to.
+     */
+    private static final String MAVEN_WRAPPER_JAR_PATH =
+            ".mvn/wrapper/maven-wrapper.jar";
+
+    /**
+     * Name of the property which should be used to override the default download url for the wrapper.
+     */
+    private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+    public static void main(String args[]) {
+        System.out.println("- Downloader started");
+        File baseDirectory = new File(args[0]);
+        System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+        // If the maven-wrapper.properties exists, read it and check if it contains a custom
+        // wrapperUrl parameter.
+        File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+        String url = DEFAULT_DOWNLOAD_URL;
+        if (mavenWrapperPropertyFile.exists()) {
+            FileInputStream mavenWrapperPropertyFileInputStream = null;
+            try {
+                mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+                Properties mavenWrapperProperties = new Properties();
+                mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+                url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+            } catch (IOException e) {
+                System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+            } finally {
+                try {
+                    if (mavenWrapperPropertyFileInputStream != null) {
+                        mavenWrapperPropertyFileInputStream.close();
+                    }
+                } catch (IOException e) {
+                    // Ignore ...
+                }
+            }
+        }
+        System.out.println("- Downloading from: " + url);
+
+        File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+        if (!outputFile.getParentFile().exists()) {
+            if (!outputFile.getParentFile().mkdirs()) {
+                System.out.println(
+                        "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+            }
+        }
+        System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+        try {
+            downloadFileFromURL(url, outputFile);
+            System.out.println("Done");
+            System.exit(0);
+        } catch (Throwable e) {
+            System.out.println("- Error downloading");
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+        if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+            String username = System.getenv("MVNW_USERNAME");
+            char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+            Authenticator.setDefault(new Authenticator() {
+                @Override
+                protected PasswordAuthentication getPasswordAuthentication() {
+                    return new PasswordAuthentication(username, password);
+                }
+            });
+        }
+        URL website = new URL(urlString);
+        ReadableByteChannel rbc;
+        rbc = Channels.newChannel(website.openStream());
+        FileOutputStream fos = new FileOutputStream(destination);
+        fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+        fos.close();
+        rbc.close();
+    }
+
+}

BIN
.mvn/wrapper/maven-wrapper.jar


+ 2 - 0
.mvn/wrapper/maven-wrapper.properties

@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar

+ 83 - 0
catalina.out

@@ -0,0 +1,83 @@
+2020-01-02 14:10:49.643  INFO 13620 --- [main] com.caimei.CaimeiMallAdminApplication    : Starting CaimeiMallAdminApplication on caimei-lijun with PID 13620 (E:\caimei-mall-admin\target\classes started by 365 in E:\caimei-mall-admin)
+2020-01-02 14:10:49.884  INFO 13620 --- [main] com.caimei.CaimeiMallAdminApplication    : The following profiles are active: dev
+2020-01-02 14:10:54.150  INFO 13620 --- [main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@31368b99: startup date [Thu Jan 02 14:10:53 CST 2020]; root of context hierarchy
+2020-01-02 14:10:57.133  WARN 13620 --- [main] o.m.s.mapper.ClassPathMapperScanner      : No MyBatis mapper was found in '[com.caimei]' package. Please check your configuration.
+2020-01-02 14:11:07.930  INFO 13620 --- [main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8108 (http)
+2020-01-02 14:11:08.026  INFO 13620 --- [main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
+2020-01-02 14:11:08.027  INFO 13620 --- [main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.23
+2020-01-02 14:11:09.170  INFO 13620 --- [localhost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
+2020-01-02 14:11:09.171  INFO 13620 --- [localhost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 15700 ms
+2020-01-02 14:11:09.322  INFO 13620 --- [localhost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
+2020-01-02 14:11:09.327  INFO 13620 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
+2020-01-02 14:11:09.327  INFO 13620 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
+2020-01-02 14:11:09.328  INFO 13620 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
+2020-01-02 14:11:09.328  INFO 13620 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
+2020-01-02 14:11:11.087  INFO 13620 --- [main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@31368b99: startup date [Thu Jan 02 14:10:53 CST 2020]; root of context hierarchy
+2020-01-02 14:11:11.145  INFO 13620 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
+2020-01-02 14:11:11.146  INFO 13620 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
+2020-01-02 14:11:11.177  INFO 13620 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
+2020-01-02 14:11:11.177  INFO 13620 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
+2020-01-02 14:11:11.214  INFO 13620 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
+2020-01-02 14:11:11.257  WARN 13620 --- [main] .t.AbstractTemplateResolverConfiguration : Cannot find template location: classpath:/templates/ (please add some templates or check your Thymeleaf configuration)
+2020-01-02 14:11:13.484  INFO 13620 --- [main] oConfiguration$WelcomePageHandlerMapping : Adding welcome page: class path resource [public/index.html]
+2020-01-02 14:11:22.174  INFO 13620 --- [main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
+2020-01-02 14:11:22.274  INFO 13620 --- [main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8108 (http)
+2020-01-02 14:11:22.280  INFO 13620 --- [main] com.caimei.CaimeiMallAdminApplication    : Started CaimeiMallAdminApplication in 35.802 seconds (JVM running for 60.193)
+2020-01-02 14:20:06.750  INFO 6568 --- [main] com.caimei.CaimeiMallAdminApplication    : Starting CaimeiMallAdminApplication on caimei-lijun with PID 6568 (E:\caimei-mall-admin\target\classes started by 365 in E:\caimei-mall-admin)
+2020-01-02 14:20:06.773  INFO 6568 --- [main] com.caimei.CaimeiMallAdminApplication    : The following profiles are active: dev
+2020-01-02 14:20:07.198  INFO 6568 --- [main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@36060e: startup date [Thu Jan 02 14:20:07 CST 2020]; root of context hierarchy
+2020-01-02 14:20:08.198  WARN 6568 --- [main] o.m.s.mapper.ClassPathMapperScanner      : No MyBatis mapper was found in '[com.caimei]' package. Please check your configuration.
+2020-01-02 14:20:09.460  INFO 6568 --- [main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8108 (http)
+2020-01-02 14:20:09.474  INFO 6568 --- [main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
+2020-01-02 14:20:09.475  INFO 6568 --- [main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.23
+2020-01-02 14:20:09.722  INFO 6568 --- [localhost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
+2020-01-02 14:20:09.723  INFO 6568 --- [localhost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2525 ms
+2020-01-02 14:20:09.977  INFO 6568 --- [localhost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
+2020-01-02 14:20:09.985  INFO 6568 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
+2020-01-02 14:20:09.986  INFO 6568 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
+2020-01-02 14:20:09.987  INFO 6568 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
+2020-01-02 14:20:09.987  INFO 6568 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
+2020-01-02 14:20:10.749  INFO 6568 --- [main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@36060e: startup date [Thu Jan 02 14:20:07 CST 2020]; root of context hierarchy
+2020-01-02 14:20:10.878  INFO 6568 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
+2020-01-02 14:20:10.880  INFO 6568 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
+2020-01-02 14:20:10.940  INFO 6568 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
+2020-01-02 14:20:10.940  INFO 6568 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
+2020-01-02 14:20:11.041  INFO 6568 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
+2020-01-02 14:20:11.146  WARN 6568 --- [main] .t.AbstractTemplateResolverConfiguration : Cannot find template location: classpath:/templates/ (please add some templates or check your Thymeleaf configuration)
+2020-01-02 14:20:11.639  INFO 6568 --- [main] oConfiguration$WelcomePageHandlerMapping : Adding welcome page: class path resource [public/index.html]
+2020-01-02 14:20:12.468  INFO 6568 --- [main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
+2020-01-02 14:20:12.544  INFO 6568 --- [main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8108 (http)
+2020-01-02 14:20:12.550  INFO 6568 --- [main] com.caimei.CaimeiMallAdminApplication    : Started CaimeiMallAdminApplication in 6.616 seconds (JVM running for 11.209)
+2020-01-02 14:20:20.947  INFO 6568 --- [http-nio-8108-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
+2020-01-02 14:20:20.948  INFO 6568 --- [http-nio-8108-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
+2020-01-02 14:20:21.018  INFO 6568 --- [http-nio-8108-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 69 ms
+2020-01-02 14:20:52.664  INFO 6568 --- [Thread-14] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@36060e: startup date [Thu Jan 02 14:20:07 CST 2020]; root of context hierarchy
+2020-01-02 14:20:52.667  INFO 6568 --- [Thread-14] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown
+2020-01-02 14:33:46.072  INFO 3256 --- [main] com.caimei.CaimeiMallAdminApplication    : Starting CaimeiMallAdminApplication on caimei-lijun with PID 3256 (E:\caimei-mall-admin\target\classes started by 365 in E:\caimei-mall-admin)
+2020-01-02 14:33:46.078  INFO 3256 --- [main] com.caimei.CaimeiMallAdminApplication    : The following profiles are active: dev
+2020-01-02 14:33:46.734  INFO 3256 --- [main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@52e7a6b2: startup date [Thu Jan 02 14:33:46 CST 2020]; root of context hierarchy
+2020-01-02 14:33:48.446  WARN 3256 --- [main] o.m.s.mapper.ClassPathMapperScanner      : No MyBatis mapper was found in '[com.caimei]' package. Please check your configuration.
+2020-01-02 14:33:51.932  INFO 3256 --- [main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8108 (http)
+2020-01-02 14:33:51.957  INFO 3256 --- [main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
+2020-01-02 14:33:51.960  INFO 3256 --- [main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.23
+2020-01-02 14:33:52.316  INFO 3256 --- [localhost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
+2020-01-02 14:33:52.317  INFO 3256 --- [localhost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 5590 ms
+2020-01-02 14:33:52.811  INFO 3256 --- [localhost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
+2020-01-02 14:33:52.829  INFO 3256 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
+2020-01-02 14:33:52.830  INFO 3256 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
+2020-01-02 14:33:52.831  INFO 3256 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
+2020-01-02 14:33:52.833  INFO 3256 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
+2020-01-02 14:33:53.909  INFO 3256 --- [main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@52e7a6b2: startup date [Thu Jan 02 14:33:46 CST 2020]; root of context hierarchy
+2020-01-02 14:33:54.145  INFO 3256 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
+2020-01-02 14:33:54.147  INFO 3256 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
+2020-01-02 14:33:54.273  INFO 3256 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
+2020-01-02 14:33:54.275  INFO 3256 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
+2020-01-02 14:33:54.430  INFO 3256 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
+2020-01-02 14:33:54.633  WARN 3256 --- [main] .t.AbstractTemplateResolverConfiguration : Cannot find template location: classpath:/templates/ (please add some templates or check your Thymeleaf configuration)
+2020-01-02 14:33:55.768  INFO 3256 --- [main] oConfiguration$WelcomePageHandlerMapping : Adding welcome page: class path resource [public/index.html]
+2020-01-02 14:33:59.638  INFO 3256 --- [main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
+2020-01-02 14:33:59.816  INFO 3256 --- [main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8108 (http)
+2020-01-02 14:33:59.829  INFO 3256 --- [main] com.caimei.CaimeiMallAdminApplication    : Started CaimeiMallAdminApplication in 14.68 seconds (JVM running for 16.768)
+2020-01-02 14:34:04.802  INFO 3256 --- [http-nio-8108-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
+2020-01-02 14:34:04.803  INFO 3256 --- [http-nio-8108-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
+2020-01-02 14:34:04.855  INFO 3256 --- [http-nio-8108-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 51 ms

+ 310 - 0
mvnw

@@ -0,0 +1,310 @@
+#!/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
+#
+#    https://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 Mingw, 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)`"
+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
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Found .mvn/wrapper/maven-wrapper.jar"
+    fi
+else
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+    fi
+    if [ -n "$MVNW_REPOURL" ]; then
+      jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+    else
+      jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+    fi
+    while IFS="=" read key value; do
+      case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+      esac
+    done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Downloading from: $jarUrl"
+    fi
+    wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+    if $cygwin; then
+      wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+    fi
+
+    if command -v wget > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found wget ... using wget"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            wget "$jarUrl" -O "$wrapperJarPath"
+        else
+            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+        fi
+    elif command -v curl > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found curl ... using curl"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            curl -o "$wrapperJarPath" "$jarUrl" -f
+        else
+            curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+        fi
+        
+    else
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Falling back to using Java to download"
+        fi
+        javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+        # For Cygwin, switch paths to Windows format before running javac
+        if $cygwin; then
+          javaClass=`cygpath --path --windows "$javaClass"`
+        fi
+        if [ -e "$javaClass" ]; then
+            if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Compiling MavenWrapperDownloader.java ..."
+                fi
+                # Compiling the Java class
+                ("$JAVA_HOME/bin/javac" "$javaClass")
+            fi
+            if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                # Running the downloader
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Running MavenWrapperDownloader.java ..."
+                fi
+                ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+            fi
+        fi
+    fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+  echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=`cygpath --path --windows "$M2_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+    MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+  $MAVEN_OPTS \
+  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+  "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

+ 182 - 0
mvnw.cmd

@@ -0,0 +1,182 @@
+@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    https://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 set title of command window
+title %0
+@REM enable echoing by 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
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+    IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Found %WRAPPER_JAR%
+    )
+) else (
+    if not "%MVNW_REPOURL%" == "" (
+        SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+    )
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Couldn't find %WRAPPER_JAR%, downloading it ...
+        echo Downloading from: %DOWNLOAD_URL%
+    )
+
+    powershell -Command "&{"^
+		"$webclient = new-object System.Net.WebClient;"^
+		"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+		"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+		"}"^
+		"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+		"}"
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Finished downloading %WRAPPER_JAR%
+    )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%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%

+ 166 - 0
pom.xml

@@ -0,0 +1,166 @@
+<?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>com.caimei</groupId>
+    <artifactId>caimei-mall-admin</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>1.5.9.RELEASE</version>
+    </parent>
+
+    <dependencies>
+        <!--spring Boot原始依赖-->
+        <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>
+
+        <!-- 添加mybatis的核心包 -->
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>1.3.1</version>
+        </dependency>
+
+        <!-- mysql的依赖 -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>5.1.21</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.6</version>
+        </dependency>
+
+        <!-- 分页插件 -->
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+            <version>1.2.3</version>
+        </dependency>
+
+        <!--模板引擎-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-thymeleaf</artifactId>
+        </dependency>
+        <!--允许不严格的html5格式出现-->
+        <dependency>
+            <groupId>net.sourceforge.nekohtml</groupId>
+            <artifactId>nekohtml</artifactId>
+            <version>1.9.22</version>
+        </dependency>
+
+        <!--springboot使用tomcat容器-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-tomcat</artifactId>
+            <scope>compile</scope>
+        </dependency>
+
+        <!--struts-->
+        <dependency>
+            <groupId>org.apache.struts</groupId>
+            <artifactId>struts2-core</artifactId>
+            <version>2.3.32</version>
+            <!--<exclusions>spring-boot-starter-->
+                <!--<exclusion>-->
+                    <!--<groupId>javassist</groupId>-->
+                    <!--<artifactId>javassist</artifactId>-->
+                <!--</exclusion>-->
+            <!--</exclusions>-->
+        </dependency>
+
+        <!--shiro-->
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-spring</artifactId>
+            <version>1.4.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>2.3</version>
+        </dependency>
+
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>dev</id>
+            <properties>
+                <!-- 环境标识,需要与配置文件的名称相对应 -->
+                <activatedProperties>dev</activatedProperties>
+            </properties>
+            <activation>
+                <!-- 默认环境 -->
+                <activeByDefault>true</activeByDefault>
+            </activation>
+        </profile>
+        <profile>
+            <id>test</id>
+            <properties>
+                <activatedProperties>test</activatedProperties>
+            </properties>
+        </profile>
+        <profile>
+            <id>prod</id>
+            <properties>
+                <activatedProperties>prod</activatedProperties>
+            </properties>
+        </profile>
+    </profiles>
+
+    <build>
+        <resources>
+            <resource>
+                <!--配置文件路径  -->
+                <directory>src/main/resources</directory> <!--这里对应项目存放配置文件的目录-->
+                <!--开启filtering功能  -->
+                <filtering>true</filtering>
+            </resource>
+            <resource>
+                <directory>src/main/resources/${activatedProperties}</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>1.5.2.RELEASE</version>
+                <configuration>
+                    <mainClass>com.caimei.CaimeiMallAdminApplication</mainClass><!--springboot启动类目录-->
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <!--创建一个自动可执行的jar或war文件 -->
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 13 - 0
src/main/java/com/caimei/CaimeiMallAdminApplication.java

@@ -0,0 +1,13 @@
+package com.caimei;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class CaimeiMallAdminApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(CaimeiMallAdminApplication.class, args);
+    }
+
+}

+ 125 - 0
src/main/java/com/caimei/modules/shiro/auth/AuthFilter.java

@@ -0,0 +1,125 @@
+package com.caimei.modules.shiro.auth;
+
+import com.alibaba.fastjson.JSON;
+import com.caimei.utils.HttpContextUtils;
+import com.google.gson.Gson;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * auth过滤器
+ */
+@Component
+public class AuthFilter extends AuthenticatingFilter {
+    /**
+     * 生成自定义token
+     *
+     * @param request
+     * @param response
+     * @return
+     * @throws Exception
+     */
+    @Override
+    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
+        //获取请求token
+        String token = getRequestToken((HttpServletRequest) request);
+        if (StringUtils.isBlank(token)) {
+            return null;
+        }
+        return new AuthToken(token);
+    }
+
+    /**
+     * 步骤1.所有请求全部拒绝访问
+     *
+     * @param request
+     * @param response
+     * @param mappedValue
+     * @return
+     */
+    @Override
+    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
+        if (((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 步骤2,拒绝访问的请求,会调用onAccessDenied方法,onAccessDenied方法先获取 token,再调用executeLogin方法
+     *
+     * @param request
+     * @param response
+     * @return
+     * @throws Exception
+     */
+    @Override
+    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+        //获取请求token,如果token不存在,直接返回
+        String token = getRequestToken((HttpServletRequest) request);
+        if (StringUtils.isBlank(token)) {
+            HttpServletResponse httpResponse = (HttpServletResponse) response;
+            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
+            httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
+            httpResponse.setCharacterEncoding("GBK");
+            Map<String, Object> result = new HashMap<>();
+            result.put("status", "-1");
+            result.put("msg", "未登录,请登录");
+            String json = new Gson().toJson(result);
+            httpResponse.getWriter().print(json);
+            return false;
+        }
+        return executeLogin(request, response);
+    }
+
+    /**
+     * 登陆失败时候调用
+     */
+    @Override
+    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
+        HttpServletResponse httpResponse = (HttpServletResponse) response;
+        httpResponse.setContentType("application/json;charset=utf-8");
+        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
+        httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
+        httpResponse.setCharacterEncoding("UTF-8");
+        try {
+            //处理登录失败的异常
+            Throwable throwable = e.getCause() == null ? e : e.getCause();
+            Map<String, Object> result = new HashMap<>();
+            result.put("status", "400");
+            result.put("msg", "登陆失败--onLoginFailure");
+            String json = JSON.toJSONString(result);
+            httpResponse.getWriter().print(json);
+        } catch (IOException e1) {
+        }
+        return false;
+    }
+
+    /**
+     * 获取请求的token
+     */
+    private String getRequestToken(HttpServletRequest httpRequest) {
+
+        //从header中获取token
+        String token = httpRequest.getHeader("token");
+        //如果header中不存在token,则从参数中获取token
+        if (StringUtils.isBlank(token)) {
+            token = httpRequest.getParameter("token");
+        }
+        return token;
+    }
+
+
+}

+ 69 - 0
src/main/java/com/caimei/modules/shiro/auth/AuthRealm.java

@@ -0,0 +1,69 @@
+package com.caimei.modules.shiro.auth;
+
+import com.caimei.modules.shiro.entity.CmMallAdminUser;
+import com.caimei.modules.shiro.entity.Permission;
+import com.caimei.modules.shiro.entity.Role;
+import com.caimei.modules.shiro.service.ShiroService;
+import com.caimei.utils.TokenEncryptUtils;
+import com.github.pagehelper.util.StringUtil;
+import org.apache.shiro.authc.*;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AuthRealm extends AuthorizingRealm {
+
+    @Autowired
+    private ShiroService shiroService;
+
+    @Override
+    /**
+     * 授权(验证权限时候调用
+     *@param  [principals]
+     *@return org.apache.shiro.authz.AuthorizationInfo
+     */
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+        //1. 从 PrincipalCollection 中来获取登录用户的信息
+        CmMallAdminUser user = (CmMallAdminUser) principals.getPrimaryPrincipal();
+        //Integer userId = user.getUserId();
+        //2.添加角色和权限
+        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
+        for (Role role : user.getRoles()) {
+            //2.1添加角色
+            simpleAuthorizationInfo.addRole(role.getRoleName());
+            for (Permission permission : role.getPermissions()) {
+                //2.1.1添加权限
+                simpleAuthorizationInfo.addStringPermission(permission.getPermission());
+            }
+        }
+        return simpleAuthorizationInfo;
+    }
+
+    @Override
+    /**
+     * 认证(登陆时候调用)
+     *@param  [token]
+     *@return org.apache.shiro.authc.AuthenticationInfo
+     */
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+        String accessToken = TokenEncryptUtils.decoded((String) token.getPrincipal());
+        //2. token失效
+        String[] tokens = accessToken.split("#,#");
+        if (StringUtil.isEmpty(accessToken) || Integer.parseInt(tokens[0]) < (System.currentTimeMillis() / 1000)) {
+            throw new IncorrectCredentialsException("token失效,请重新登录");
+        }
+        //3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录
+        CmMallAdminUser user = shiroService.findByUserId(Integer.valueOf(tokens[1]));
+        //4. 若用户不存在, 则可以抛出 UnknownAccountException 异常
+        if (user == null) {
+            throw new UnknownAccountException("用户不存在!");
+        }
+        //5. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo
+        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, accessToken, this.getName());
+        return info;
+    }
+}

+ 22 - 0
src/main/java/com/caimei/modules/shiro/auth/AuthToken.java

@@ -0,0 +1,22 @@
+package com.caimei.modules.shiro.auth;
+
+import org.apache.shiro.authc.UsernamePasswordToken;
+
+public class AuthToken extends UsernamePasswordToken {
+
+    private String token;
+
+    public AuthToken(String token) {
+        this.token = token;
+    }
+
+    @Override
+    public Object getPrincipal() {
+        return token;
+    }
+
+    @Override
+    public Object getCredentials() {
+        return token;
+    }
+}

+ 62 - 0
src/main/java/com/caimei/modules/shiro/auth/ShiroConfig.java

@@ -0,0 +1,62 @@
+package com.caimei.modules.shiro.auth;
+
+import org.apache.shiro.spring.LifecycleBeanPostProcessor;
+import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
+import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.servlet.Filter;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * @Author plf
+ * @Date 2019/12/30 21:50
+ * @Version 1.0
+ */
+@Configuration
+public class ShiroConfig {
+
+    @Bean("securityManager")
+    public DefaultWebSecurityManager securityManager(AuthRealm authRealm) {
+        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+        //设置自定义的Realm
+        securityManager.setRealm(authRealm);
+        securityManager.setRememberMeManager(null);
+        return securityManager;
+    }
+
+    @Bean("shiroFilter")
+    public ShiroFilterFactoryBean shirFilter(DefaultWebSecurityManager securityManager) {
+        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
+        shiroFilter.setSecurityManager(securityManager);
+        //自定义过滤(关键)
+        Map<String, Filter> filters = new HashMap<>();
+        filters.put("auth", new AuthFilter());
+        shiroFilter.setFilters(filters);
+        Map<String, String> filterMap = new LinkedHashMap<>();
+        filterMap.put("/user/login", "anon");
+        filterMap.put("/", "anon");
+        filterMap.put("/**", "auth");
+        shiroFilter.setFilterChainDefinitionMap(filterMap);
+        //这里不需要设置什么登陆路径之类的
+       /* //设置登录的请求
+        shiroFilter.setLoginUrl("/user/login");*/
+        return shiroFilter;
+    }
+
+    @Bean("lifecycleBeanPostProcessor")
+    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
+        return new LifecycleBeanPostProcessor();
+    }
+
+    @Bean
+    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
+        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
+        advisor.setSecurityManager(securityManager);
+        return advisor;
+    }
+}

+ 38 - 0
src/main/java/com/caimei/modules/shiro/auth/TokenGenerator.java

@@ -0,0 +1,38 @@
+package com.caimei.modules.shiro.auth;
+
+import java.security.MessageDigest;
+import java.util.UUID;
+
+public class TokenGenerator {
+
+    public static String generateValue() {
+        return generateValue(UUID.randomUUID().toString());
+    }
+
+    private static final char[] hexCode = "0123456789abcdef".toCharArray();
+
+    public static String toHexString(byte[] data) {
+        if (data == null) {
+            return null;
+        }
+        StringBuilder r = new StringBuilder(data.length * 2);
+        for (byte b : data) {
+            r.append(hexCode[(b >> 4) & 0xF]);
+            r.append(hexCode[(b & 0xF)]);
+        }
+        return r.toString();
+    }
+
+    public static String generateValue(String param) {
+        try {
+            MessageDigest algorithm = MessageDigest.getInstance("MD5");
+            algorithm.reset();
+            algorithm.update(param.getBytes());
+            byte[] messageDigest = algorithm.digest();
+            return toHexString(messageDigest);
+        } catch (Exception e) {
+            throw new RuntimeException("生成Token失败");
+        }
+    }
+}
+

+ 53 - 0
src/main/java/com/caimei/modules/shiro/controller/ShiroController.java

@@ -0,0 +1,53 @@
+package com.caimei.modules.shiro.controller;
+
+
+import com.caimei.modules.shiro.entity.CmMallAdminUser;
+import com.caimei.modules.shiro.service.ShiroService;
+import com.caimei.utils.JsonModel;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@RestController
+@RequestMapping("/user")
+public class ShiroController {
+
+    @Autowired
+    private ShiroService shiroService;
+
+
+    /**
+     * 登录
+     */
+    @GetMapping("/login")
+    public JsonModel login(String account, String password, Integer organizeID) {
+        JsonModel jsonModel = JsonModel.newInstance();
+        //用户信息
+        CmMallAdminUser user = shiroService.findByUsername(account, organizeID);
+        //账号不存在、密码错误
+        if (user == null || !user.getPassword().equals(password)) {
+            return jsonModel.error("账号或密码有误");
+        } else {
+            //生成token
+            String token = null;
+            try {
+                token = shiroService.createToken(user);
+            } catch (Exception e) {
+                return jsonModel.error("生成token失败");
+            }
+            return jsonModel.success(token);
+        }
+    }
+
+    @GetMapping("/info")
+    public JsonModel info(String token) {
+        String[] tokens = token.split("#,#");
+        //用户信息
+        CmMallAdminUser user = shiroService.findByUserId(Integer.valueOf(tokens[1]));
+        return JsonModel.newInstance().success(user);
+    }
+}
+
+

+ 12 - 0
src/main/java/com/caimei/modules/shiro/dao/SysTokenRepository.java

@@ -0,0 +1,12 @@
+package com.caimei.modules.shiro.dao;
+
+
+import com.caimei.modules.shiro.entity.SysToken;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface SysTokenRepository {
+    SysToken findByToken(String accessToken);
+
+    SysToken findByUserId(Integer userId);
+}

+ 13 - 0
src/main/java/com/caimei/modules/shiro/dao/UserMapper.java

@@ -0,0 +1,13 @@
+package com.caimei.modules.shiro.dao;
+
+
+import com.caimei.modules.shiro.entity.CmMallAdminUser;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+@Mapper
+public interface UserMapper {
+    CmMallAdminUser findByUsername(@Param("account") String account, @Param("organizeID") Integer organizeID);
+
+    CmMallAdminUser findByUserId(Integer id);
+}

+ 70 - 0
src/main/java/com/caimei/modules/shiro/entity/CmMallAdminUser.java

@@ -0,0 +1,70 @@
+package com.caimei.modules.shiro.entity;
+
+import java.util.Date;
+import java.util.Set;
+
+public class CmMallAdminUser {
+    private Integer id;
+    private String account;
+    private String password;
+    private Integer organizeID;
+    private Date addTime;
+    private Date updateTime;
+    private Set<Role> roles;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getAccount() {
+        return account;
+    }
+
+    public void setAccount(String account) {
+        this.account = account;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public Integer getOrganizeID() {
+        return organizeID;
+    }
+
+    public void setOrganizeID(Integer organizeID) {
+        this.organizeID = organizeID;
+    }
+
+    public Date getAddTime() {
+        return addTime;
+    }
+
+    public void setAddTime(Date addTime) {
+        this.addTime = addTime;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public Set<Role> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(Set<Role> roles) {
+        this.roles = roles;
+    }
+}

+ 33 - 0
src/main/java/com/caimei/modules/shiro/entity/Permission.java

@@ -0,0 +1,33 @@
+package com.caimei.modules.shiro.entity;
+
+
+public class Permission {
+
+    private Integer permissionId;
+    private String permissionName;
+    private String permission;
+
+    public Integer getPermissionId() {
+        return permissionId;
+    }
+
+    public void setPermissionId(Integer permissionId) {
+        this.permissionId = permissionId;
+    }
+
+    public String getPermissionName() {
+        return permissionName;
+    }
+
+    public void setPermissionName(String permissionName) {
+        this.permissionName = permissionName;
+    }
+
+    public String getPermission() {
+        return permission;
+    }
+
+    public void setPermission(String permission) {
+        this.permission = permission;
+    }
+}

+ 35 - 0
src/main/java/com/caimei/modules/shiro/entity/Role.java

@@ -0,0 +1,35 @@
+package com.caimei.modules.shiro.entity;
+
+
+import java.util.Set;
+
+public class Role {
+
+    private Integer roleId;
+    private String roleName;
+    private Set<Permission> permissions;
+
+    public Integer getRoleId() {
+        return roleId;
+    }
+
+    public void setRoleId(Integer roleId) {
+        this.roleId = roleId;
+    }
+
+    public String getRoleName() {
+        return roleName;
+    }
+
+    public void setRoleName(String roleName) {
+        this.roleName = roleName;
+    }
+
+    public Set<Permission> getPermissions() {
+        return permissions;
+    }
+
+    public void setPermissions(Set<Permission> permissions) {
+        this.permissions = permissions;
+    }
+}

+ 60 - 0
src/main/java/com/caimei/modules/shiro/entity/SysToken.java

@@ -0,0 +1,60 @@
+package com.caimei.modules.shiro.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+public class SysToken implements Serializable {
+
+    /**
+     * 用户ID
+     */
+    private Integer userId;
+
+    /**
+     * token
+     */
+    private String token;
+
+    /**
+     * 过期时间
+     */
+    private Date expireTime;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public Date getExpireTime() {
+        return expireTime;
+    }
+
+    public void setExpireTime(Date expireTime) {
+        this.expireTime = expireTime;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+}

+ 13 - 0
src/main/java/com/caimei/modules/shiro/service/ShiroService.java

@@ -0,0 +1,13 @@
+package com.caimei.modules.shiro.service;
+
+
+import com.caimei.modules.shiro.entity.CmMallAdminUser;
+
+public interface ShiroService {
+
+    CmMallAdminUser findByUsername(String account, Integer organizeID);
+
+    String createToken(CmMallAdminUser user) throws Exception;
+
+    CmMallAdminUser findByUserId(Integer id);
+}

+ 45 - 0
src/main/java/com/caimei/modules/shiro/service/impl/ShiroServiceImpl.java

@@ -0,0 +1,45 @@
+package com.caimei.modules.shiro.service.impl;
+
+
+import com.caimei.modules.shiro.dao.SysTokenRepository;
+import com.caimei.modules.shiro.dao.UserMapper;
+import com.caimei.modules.shiro.entity.CmMallAdminUser;
+import com.caimei.modules.shiro.service.ShiroService;
+import com.caimei.utils.MD5Util;
+import com.caimei.utils.TokenEncryptUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ShiroServiceImpl implements ShiroService {
+    @Autowired
+    private UserMapper userMapper;
+    @Autowired
+    private SysTokenRepository sysTokenRepository;
+
+    /**
+     * 根据account查找用户
+     *
+     * @param account
+     * @return User
+     */
+    @Override
+    public CmMallAdminUser findByUsername(String account, Integer organizeID) {
+        CmMallAdminUser user = userMapper.findByUsername(account, organizeID);
+        return user;
+    }
+
+    @Override
+    public String createToken(CmMallAdminUser user) throws Exception {
+        // 获取当前时间戳(10位整数)
+        int time = (int) (System.currentTimeMillis() / 1000 + 3600);
+        String password = MD5Util.MD5(user.getPassword());
+        String token = TokenEncryptUtils.encoded(time + "#,#" + user.getId() + "#,#" + password);
+        return token;
+    }
+
+    @Override
+    public CmMallAdminUser findByUserId(Integer id) {
+        return userMapper.findByUserId(id);
+    }
+}

+ 23 - 0
src/main/java/com/caimei/utils/HttpContextUtils.java

@@ -0,0 +1,23 @@
+package com.caimei.utils;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+
+public class HttpContextUtils {
+    public static HttpServletRequest getHttpServletRequest() {
+        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+    }
+
+    public static String getDomain(){
+        HttpServletRequest request = getHttpServletRequest();
+        StringBuffer url = request.getRequestURL();
+        return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
+    }
+
+    public static String getOrigin(){
+        HttpServletRequest request = getHttpServletRequest();
+        return request.getHeader("Origin");
+    }
+}

+ 113 - 0
src/main/java/com/caimei/utils/JsonModel.java

@@ -0,0 +1,113 @@
+package com.caimei.utils;
+
+import com.alibaba.fastjson.JSONObject;
+
+import java.io.Serializable;
+
+public class JsonModel implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String code;  //状态码 1成功 -1失败
+    private String msg;    //提示信息
+    private Object data;        //返回结果
+
+
+    public static JsonModel newInstance() {
+        JsonModel jsonModel = new JsonModel();
+        return jsonModel.success();
+    }
+
+    public JsonModel unLogin() {
+        this.setMsg("请先登录");
+        this.setCode("1002");
+        return this;
+    }
+
+    public JsonModel success() {
+        this.code = "1";
+        this.msg = "操作成功";
+        return this;
+    }
+
+    public JsonModel success(Object data) {
+        this.code = "1";
+        this.msg = "操作成功";
+        this.data = data;
+        return this;
+    }
+
+    public JsonModel success(String msg, Object data) {
+        this.code = "1";
+        this.msg = msg;
+        this.data = data;
+        return this;
+    }
+
+    public JsonModel success(String code, Object data, String msg) {
+        this.code = code;
+        this.msg = msg;
+        this.data = data;
+        return this;
+    }
+
+
+    public JsonModel error() {
+        this.code = "-1";
+        this.msg = "操作失败";
+        return this;
+    }
+
+    public JsonModel error(String msg) {
+        this.code = "-1";
+        this.msg = msg;
+        return this;
+    }
+
+    public JsonModel error(String code, String msg) {
+        this.code = code;
+        this.msg = msg;
+        return this;
+    }
+
+    public JsonModel error(String code, Object data, String msg) {
+        this.code = code;
+        this.msg = msg;
+        this.data = data;
+        return this;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+
+    @Override
+    public String toString() {
+        return "JsonModel [code=" + code + ", msg=" + msg + ", data=" + data + "]";
+    }
+
+    public String toJsonString() {
+        return JSONObject.toJSONString(this);
+    }
+
+}

+ 82 - 0
src/main/java/com/caimei/utils/MD5Util.java

@@ -0,0 +1,82 @@
+/**  
+ * Project Name:caiMeiCRM  
+ * File Name:MD5Util.java  
+ * Package Name:com.caimei.base.utils  
+ * Date:2015-1-15下午1:27:25  
+ * Copyright (c) 2015, 1722948843@qq.com.com All Rights Reserved.  
+ *  
+*/  
+  
+package com.caimei.utils;  
+
+import java.security.MessageDigest;
+
+/**  
+ * ClassName:MD5Util <br/>  
+ * Function: TODO ADD FUNCTION. <br/>  
+ * Reason:   TODO ADD REASON. <br/>  
+ * Date:     2015-1-15 下午1:27:25 <br/>  
+ * @author   822  
+ * @version    
+ * @since    JDK 1.6  
+ * @see        
+ */
+public class MD5Util {
+
+	/* ***************************************************
+	 	TODO 2018-5-9 此工具类已经整合至com.caimei.utils.MD5Utils
+	 */
+	public static String MD5(String s) throws Exception {
+		if (s.trim() == null) {
+			return "null";
+		}
+		MessageDigest messagedigest = MessageDigest.getInstance("MD5");
+		byte[] abyte0 = s.getBytes("utf-8");
+		byte[] abyte1 = messagedigest.digest(abyte0);
+		return bytes2Hex(abyte1).toUpperCase();
+	}
+
+	private static String bytes2Hex(byte[] b) {
+		String s = "";
+		for (int i = 0; i < b.length; ++i) {
+			String s1 = Integer.toHexString(b[i] & 0xFF);
+			if (s1.length() == 1) {
+				s = s + "0";
+			}
+			s = s + s1;
+		}
+
+		return s;
+	}
+	
+	/**
+	 * <p>Description: 16位的MD5值</p>
+	 * <p>Company: caimei365</p> 
+	 * @author dmeng
+	 * @date 2015年12月17日 下午5:28:49
+	 * @param s
+	 * @return
+	 * @throws Exception
+	 */
+	public static String MD5To16Bit(String s) throws Exception {
+		MessageDigest md = MessageDigest.getInstance("MD5");
+		md.update(s.getBytes());
+		byte b[] = md.digest();
+		int i;
+		StringBuffer buf = new StringBuffer("");
+		for (int offset = 0; offset < b.length; offset++) {
+			i = b[offset];
+			if (i < 0)
+				i += 256;
+			if (i < 16)
+				buf.append("0");
+			buf.append(Integer.toHexString(i));
+		}
+		return buf.toString().substring(8, 24);
+	}
+	
+	public static void main(String[] args) throws Exception{
+		System.out.println(MD5Util.MD5To16Bit("act_name=发红包测试&client_ip=127.0.0.1&max_value=132&mch_billno=100257913453645825&mch_id=10025791&min_value=132&nick_name=采美365网&nonce_str=A1ED1E437160452FAE18356985D38F43&re_openid=oVTYvt4xhmqGKSI3owBO1TdJqtYo&remark=快来抢!&send_name=采美365网&total_amount=132&total_num=1&wishing=恭喜发财,大吉大利&wxappid=wxea43a0f9ebce9e66&key=CaimeiWxpayasdklfj8sdf27sdf3DcVd"));
+		
+	}
+}

+ 94 - 0
src/main/java/com/caimei/utils/TokenEncryptUtils.java

@@ -0,0 +1,94 @@
+package com.caimei.utils;
+
+/**
+ * token编码工具类
+ *
+ * @author ouyangjun
+ */
+public class TokenEncryptUtils {
+
+    // 编码密码,可自定义
+    private static final String ENCODED_PASSWORD = "ouyangjun";
+
+    /**
+     * 编码
+     *
+     * @param str
+     * @return
+     */
+    public static String encoded(String str) {
+        return strToHex(encodedString(str, ENCODED_PASSWORD));
+    }
+
+    /**
+     * 转换
+     *
+     * @param str
+     * @param password
+     * @return
+     */
+    private static String encodedString(String str, String password) {
+        char[] pwd = password.toCharArray();
+        int pwdLen = pwd.length;
+
+        char[] strArray = str.toCharArray();
+        for (int i = 0; i < strArray.length; i++) {
+            strArray[i] = (char) (strArray[i] ^ pwd[i % pwdLen] ^ pwdLen);
+        }
+        return new String(strArray);
+    }
+
+    private static String strToHex(String s) {
+        return bytesToHexStr(s.getBytes());
+    }
+
+    private static String bytesToHexStr(byte[] bytesArray) {
+        StringBuilder builder = new StringBuilder();
+        String hexStr;
+        for (byte bt : bytesArray) {
+            hexStr = Integer.toHexString(bt & 0xFF);
+            if (hexStr.length() == 1) {
+                builder.append("0");
+                builder.append(hexStr);
+            } else {
+                builder.append(hexStr);
+            }
+        }
+        return builder.toString();
+    }
+
+    /**
+     * 解码
+     *
+     * @param str
+     * @return
+     */
+    public static String decoded(String str) {
+        String hexStr = null;
+        try {
+            hexStr = hexStrToStr(str);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        if (hexStr != null) {
+            hexStr = encodedString(hexStr, ENCODED_PASSWORD);
+        }
+        return hexStr;
+    }
+
+    private static String hexStrToStr(String hexStr) {
+        return new String(hexStrToBytes(hexStr));
+    }
+
+    private static byte[] hexStrToBytes(String hexStr) {
+        String hex;
+        int val;
+        byte[] btHexStr = new byte[hexStr.length() / 2];
+        for (int i = 0; i < btHexStr.length; i++) {
+            hex = hexStr.substring(2 * i, 2 * i + 2);
+            val = Integer.valueOf(hex, 16);
+            btHexStr[i] = (byte) val;
+        }
+        return btHexStr;
+    }
+}

+ 3 - 0
src/main/resources/application.yml

@@ -0,0 +1,3 @@
+spring:
+  profiles:
+    active: @activatedProperties@

+ 42 - 0
src/main/resources/dev/application-dev.yml

@@ -0,0 +1,42 @@
+server:
+  port: 8108
+spring:
+  application:
+    name: caimei-mall-admin #指定服务名
+
+    #数据源连接--start
+  datasource:
+    driverClassName: com.mysql.jdbc.Driver
+    url: jdbc:mysql://192.168.1.11:3306/caimei@20180509?characterEncoding=UTF8
+    username: developer
+    password: 05bZ/OxTB:X+yd%1
+    #数据源连接--end
+
+  #模板引擎配置
+  thymeleaf:
+    #路径
+    prefix: classpath:/templates/
+    #取消thymeleaf对页面的强制校验
+    content-type: text/html
+    mode:  LEGACYHTML5
+    cache: false
+
+#整合mybatis
+mybatis:
+  #加载Mybatis映射文件
+  mapper-locations: classpath:mapper/*Mapper.xml
+  #pojo别名扫描包
+  type-aliases-package: com.caimei.modules.*.entity
+
+#分页配置
+pagehelper:
+  helperDialect: mysql
+  reasonable: true
+  supportMethodsArguments: true
+  params: count=countSql
+
+#日志配置
+logging:
+  file: E:/caimei-mall-admin/catalina.out
+  level: debug
+

+ 26 - 0
src/main/resources/mapper/UserMapper.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.caimei.modules.shiro.dao.UserMapper">
+    <select id="findByUsername" resultType="com.caimei.modules.shiro.entity.CmMallAdminUser">
+        SELECT
+          *
+        FROM
+          cm_mall_admin_user
+        WHERE
+          account = #{account}
+          AND organizeID = #{organizeID}
+          AND delFlag = '0'
+    </select>
+
+    <select id="findByUserId" resultType="com.caimei.modules.shiro.entity.CmMallAdminUser" parameterType="int">
+        SELECT
+          *
+        FROM
+          cm_mall_admin_user
+        WHERE
+          id = #{id}
+          AND delFlag = '0'
+    </select>
+</mapper>

+ 43 - 0
src/main/resources/prod/application-prod.yml

@@ -0,0 +1,43 @@
+server:
+  port: 8108
+spring:
+  application:
+    name: caimei-mall-admin #指定服务名
+
+    #数据源连接--start
+  datasource:
+    driverClassName: com.mysql.jdbc.Driver
+    url: jdbc:mysql://10.104.172.219:3306/caimei?characterEncoding=UTF8
+    username: developer
+    password: diKtPYZ'wToI&9#L
+    #数据源连接--end
+
+  #模板引擎配置
+  thymeleaf:
+    #路径
+    prefix: classpath:/templates/
+    #取消thymeleaf对页面的强制校验
+    content-type: text/html
+    mode:  LEGACYHTML5
+    cache: false
+
+
+#整合mybatis
+mybatis:
+  #加载Mybatis映射文件
+  mapper-locations: classpath:mapper/*Mapper.xml
+  #pojo别名扫描包
+  type-aliases-package: com.caimei.modules.*.entity
+
+#分页配置
+pagehelper:
+  helperDialect: mysql
+  reasonable: true
+  supportMethodsArguments: true
+  params: count=countSql
+
+
+#日志配置
+logging:
+  file: /mnt/newdatadrive/data/runtime/tomcat-instance/caimei-mall-admin/catalina.out
+  level: debug

+ 19 - 0
src/main/resources/public/index.html

@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<title>采美365网-商城后台</title>
+<meta charset="UTF-8">
+<meta http-equiv="pragma" content="no-cache">
+<meta http-equiv="cache-control" content="no-cache">
+<meta http-equiv="expires" content="0">
+<meta http-equiv="X-UA-Compatible" content="IE=Edge">
+<meta http-equiv="keywords" content="采美365网-商城后台">
+<meta http-equiv="description" content="采美365网-商城后台">
+<body>
+<div class="index">
+    欢迎使用!《采美365网-商城后台》
+</div>
+</body>
+<script>
+
+</script>
+</html>

+ 42 - 0
src/main/resources/test/application-test.yml

@@ -0,0 +1,42 @@
+server:
+  port: 8108
+spring:
+  application:
+    name: caimei-mall-admin #指定服务名
+
+    #数据源连接--start
+  datasource:
+    driverClassName: com.mysql.jdbc.Driver
+    url: jdbc:mysql://10.104.50.235:3306/caimei?characterEncoding=UTF8
+    username: developer
+    password: J5p";~OVazNl%y)?
+    #数据源连接--end
+
+  #模板引擎配置
+  thymeleaf:
+    #路径
+    prefix: classpath:/templates/
+    #取消thymeleaf对页面的强制校验
+    content-type: text/html
+    mode:  LEGACYHTML5
+    cache: false
+
+
+#整合mybatis
+mybatis:
+  #加载Mybatis映射文件
+  mapper-locations: classpath:mapper/*Mapper.xml
+  #pojo别名扫描包
+  type-aliases-package: com.caimei.modules.*.entity
+
+#分页配置
+pagehelper:
+  helperDialect: mysql
+  reasonable: true
+  supportMethodsArguments: true
+  params: count=countSql
+
+#日志配置
+logging:
+  file: /mnt/newdatadrive/data/runtime/tomcat-instance/caimei-mall-admin/catalina.out
+  level: debug

+ 113 - 0
src/test/java/com/caimei/TokenUtils.java

@@ -0,0 +1,113 @@
+package com.caimei;
+
+import com.caimei.utils.TokenEncryptUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * token生成和校验
+ *
+ * @author plf
+ */
+public class TokenUtils {
+
+    private static Map<String, String> MAP_TOKENS = new HashMap<String, String>();
+    private static final int VALID_TIME = 60 * 60 * 2; // token有效期(秒)
+    public static final String TOKEN_ERROR = "F"; // 非法
+    public static final String TOKEN_OVERDUE = "G"; // 过期
+    public static final String TOKEN_FAILURE = "S"; // 失效
+
+    /**
+     * 生成token,该token长度不一致,如需一致,可自行MD5或者其它方式加密一下
+     * 该方式的token只存在磁盘上,如果项目是分布式,最好用redis存储
+     *
+     * @param str: 该字符串可自定义,在校验token时要保持一致
+     * @return
+     */
+    public static String getToken(String str) {
+        String token = TokenEncryptUtils.encoded(getCurrentTime() + "," + str);
+        MAP_TOKENS.put(str, token);
+        return token;
+    }
+
+    /**
+     * 校验token的有效性
+     *
+     * @param token
+     * @return
+     */
+    public static String checkToken(String token) {
+        if (token == null) {
+            return TOKEN_ERROR;
+        }
+        try {
+            String[] tArr = TokenEncryptUtils.decoded(token).split(",");
+            if (tArr.length != 2) {
+                return TOKEN_ERROR;
+            }
+            // token生成时间戳
+            int tokenTime = Integer.parseInt(tArr[0]);
+            // 当前时间戳
+            int currentTime = getCurrentTime();
+            if (currentTime - tokenTime < VALID_TIME) {
+                String tokenStr = tArr[1];
+                String mToken = MAP_TOKENS.get(tokenStr);
+                if (mToken == null) {
+                    return TOKEN_OVERDUE;
+                } else if (!mToken.equals(token)) {
+                    return TOKEN_FAILURE;
+                }
+                return tokenStr;
+            } else {
+                return TOKEN_OVERDUE;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return TOKEN_ERROR;
+    }
+
+    /**
+     * 获取当前时间戳(10位整数)
+     */
+    public static int getCurrentTime() {
+        return (int) (System.currentTimeMillis() / 1000);
+    }
+
+    /**
+     * 移除过期的token
+     */
+    public static void removeInvalidToken() {
+        int currentTime = getCurrentTime();
+        for (Entry<String, String> entry : MAP_TOKENS.entrySet()) {
+            String[] tArr = TokenEncryptUtils.decoded(entry.getValue()).split(",");
+            int tokenTime = Integer.parseInt(tArr[0]);
+            if (currentTime - tokenTime > VALID_TIME) {
+                MAP_TOKENS.remove(entry.getKey());
+            }
+        }
+    }
+
+    /**
+     * 测试
+     *
+     * @param args
+     */
+    public static void main(String[] args) {
+        String str = "username_and_password";
+
+        // 获取token
+        String token = TokenUtils.getToken(str);
+        System.out.println("token Result: " + token);
+
+        // 校验token
+        String checkToken = TokenUtils.checkToken(token);
+        System.out.println("checkToken Result: " + checkToken);
+        if (str.equals(checkToken)) {
+            System.out.println("==>token verification succeeded!");
+        }
+
+    }
+}