瀏覽代碼

jhipster generated source

Kr Younger 6 年之前
當前提交
c05ac20763
共有 100 個文件被更改,包括 25917 次插入0 次删除
  1. 24
    0
      .editorconfig
  2. 149
    0
      .gitattributes
  3. 144
    0
      .gitignore
  4. 5
    0
      .huskyrc
  5. 110
    0
      .mvn/wrapper/MavenWrapperDownloader.java
  6. 二進制
      .mvn/wrapper/maven-wrapper.jar
  7. 1
    0
      .mvn/wrapper/maven-wrapper.properties
  8. 2
    0
      .prettierignore
  9. 12
    0
      .prettierrc
  10. 36
    0
      .yo-rc.json
  11. 105
    0
      README.md
  12. 39
    0
      angular.json
  13. 286
    0
      mvnw
  14. 161
    0
      mvnw.cmd
  15. 19023
    0
      package-lock.json
  16. 126
    0
      package.json
  17. 1154
    0
      pom.xml
  18. 5
    0
      postcss.config.js
  19. 7
    0
      proxy.conf.json
  20. 14
    0
      src/main/docker/.dockerignore
  21. 20
    0
      src/main/docker/Dockerfile
  22. 32
    0
      src/main/docker/app.yml
  23. 12
    0
      src/main/docker/elasticsearch.yml
  24. 4
    0
      src/main/docker/entrypoint.sh
  25. 15
    0
      src/main/docker/kafka.yml
  26. 11
    0
      src/main/docker/postgresql.yml
  27. 7
    0
      src/main/docker/sonar.yml
  28. 21
    0
      src/main/java/io/github/jhipster/application/ApplicationWebXml.java
  29. 98
    0
      src/main/java/io/github/jhipster/application/PrivyBlogApp.java
  30. 98
    0
      src/main/java/io/github/jhipster/application/aop/logging/LoggingAspect.java
  31. 14
    0
      src/main/java/io/github/jhipster/application/config/ApplicationProperties.java
  32. 59
    0
      src/main/java/io/github/jhipster/application/config/AsyncConfiguration.java
  33. 44
    0
      src/main/java/io/github/jhipster/application/config/CacheConfiguration.java
  34. 28
    0
      src/main/java/io/github/jhipster/application/config/CloudDatabaseConfiguration.java
  35. 17
    0
      src/main/java/io/github/jhipster/application/config/Constants.java
  36. 62
    0
      src/main/java/io/github/jhipster/application/config/DatabaseConfiguration.java
  37. 20
    0
      src/main/java/io/github/jhipster/application/config/DateTimeFormatConfiguration.java
  38. 51
    0
      src/main/java/io/github/jhipster/application/config/DefaultProfileUtil.java
  39. 72
    0
      src/main/java/io/github/jhipster/application/config/ElasticsearchConfiguration.java
  40. 63
    0
      src/main/java/io/github/jhipster/application/config/JacksonConfiguration.java
  41. 53
    0
      src/main/java/io/github/jhipster/application/config/LiquibaseConfiguration.java
  42. 27
    0
      src/main/java/io/github/jhipster/application/config/LocaleConfiguration.java
  43. 19
    0
      src/main/java/io/github/jhipster/application/config/LoggingAspectConfiguration.java
  44. 156
    0
      src/main/java/io/github/jhipster/application/config/LoggingConfiguration.java
  45. 41
    0
      src/main/java/io/github/jhipster/application/config/MessagingConfiguration.java
  46. 126
    0
      src/main/java/io/github/jhipster/application/config/MetricsConfiguration.java
  47. 123
    0
      src/main/java/io/github/jhipster/application/config/SecurityConfiguration.java
  48. 206
    0
      src/main/java/io/github/jhipster/application/config/WebConfigurer.java
  49. 82
    0
      src/main/java/io/github/jhipster/application/config/WebsocketConfiguration.java
  50. 35
    0
      src/main/java/io/github/jhipster/application/config/WebsocketSecurityConfiguration.java
  51. 86
    0
      src/main/java/io/github/jhipster/application/config/audit/AuditEventConverter.java
  52. 4
    0
      src/main/java/io/github/jhipster/application/config/audit/package-info.java
  53. 4
    0
      src/main/java/io/github/jhipster/application/config/package-info.java
  54. 79
    0
      src/main/java/io/github/jhipster/application/domain/AbstractAuditingEntity.java
  55. 62
    0
      src/main/java/io/github/jhipster/application/domain/Authority.java
  56. 110
    0
      src/main/java/io/github/jhipster/application/domain/PersistentAuditEvent.java
  57. 235
    0
      src/main/java/io/github/jhipster/application/domain/User.java
  58. 4
    0
      src/main/java/io/github/jhipster/application/domain/package-info.java
  59. 11
    0
      src/main/java/io/github/jhipster/application/repository/AuthorityRepository.java
  60. 89
    0
      src/main/java/io/github/jhipster/application/repository/CustomAuditEventRepository.java
  61. 25
    0
      src/main/java/io/github/jhipster/application/repository/PersistenceAuditEventRepository.java
  62. 47
    0
      src/main/java/io/github/jhipster/application/repository/UserRepository.java
  63. 4
    0
      src/main/java/io/github/jhipster/application/repository/package-info.java
  64. 10
    0
      src/main/java/io/github/jhipster/application/repository/search/UserSearchRepository.java
  65. 4
    0
      src/main/java/io/github/jhipster/application/repository/search/package-info.java
  66. 16
    0
      src/main/java/io/github/jhipster/application/security/AuthoritiesConstants.java
  67. 62
    0
      src/main/java/io/github/jhipster/application/security/DomainUserDetailsService.java
  68. 76
    0
      src/main/java/io/github/jhipster/application/security/SecurityUtils.java
  69. 20
    0
      src/main/java/io/github/jhipster/application/security/SpringSecurityAuditorAware.java
  70. 19
    0
      src/main/java/io/github/jhipster/application/security/UserNotActivatedException.java
  71. 21
    0
      src/main/java/io/github/jhipster/application/security/jwt/JWTConfigurer.java
  72. 54
    0
      src/main/java/io/github/jhipster/application/security/jwt/JWTFilter.java
  73. 119
    0
      src/main/java/io/github/jhipster/application/security/jwt/TokenProvider.java
  74. 4
    0
      src/main/java/io/github/jhipster/application/security/package-info.java
  75. 51
    0
      src/main/java/io/github/jhipster/application/service/AuditEventService.java
  76. 105
    0
      src/main/java/io/github/jhipster/application/service/MailService.java
  77. 304
    0
      src/main/java/io/github/jhipster/application/service/UserService.java
  78. 35
    0
      src/main/java/io/github/jhipster/application/service/dto/PasswordChangeDTO.java
  79. 199
    0
      src/main/java/io/github/jhipster/application/service/dto/UserDTO.java
  80. 4
    0
      src/main/java/io/github/jhipster/application/service/dto/package-info.java
  81. 76
    0
      src/main/java/io/github/jhipster/application/service/mapper/UserMapper.java
  82. 4
    0
      src/main/java/io/github/jhipster/application/service/mapper/package-info.java
  83. 4
    0
      src/main/java/io/github/jhipster/application/service/package-info.java
  84. 41
    0
      src/main/java/io/github/jhipster/application/service/util/RandomUtil.java
  85. 189
    0
      src/main/java/io/github/jhipster/application/web/rest/AccountResource.java
  86. 77
    0
      src/main/java/io/github/jhipster/application/web/rest/AuditResource.java
  87. 39
    0
      src/main/java/io/github/jhipster/application/web/rest/LogsResource.java
  88. 73
    0
      src/main/java/io/github/jhipster/application/web/rest/UserJWTController.java
  89. 213
    0
      src/main/java/io/github/jhipster/application/web/rest/UserResource.java
  90. 42
    0
      src/main/java/io/github/jhipster/application/web/rest/errors/BadRequestAlertException.java
  91. 54
    0
      src/main/java/io/github/jhipster/application/web/rest/errors/CustomParameterizedException.java
  92. 10
    0
      src/main/java/io/github/jhipster/application/web/rest/errors/EmailAlreadyUsedException.java
  93. 13
    0
      src/main/java/io/github/jhipster/application/web/rest/errors/EmailNotFoundException.java
  94. 21
    0
      src/main/java/io/github/jhipster/application/web/rest/errors/ErrorConstants.java
  95. 107
    0
      src/main/java/io/github/jhipster/application/web/rest/errors/ExceptionTranslator.java
  96. 33
    0
      src/main/java/io/github/jhipster/application/web/rest/errors/FieldErrorVM.java
  97. 16
    0
      src/main/java/io/github/jhipster/application/web/rest/errors/InternalServerErrorException.java
  98. 13
    0
      src/main/java/io/github/jhipster/application/web/rest/errors/InvalidPasswordException.java
  99. 10
    0
      src/main/java/io/github/jhipster/application/web/rest/errors/LoginAlreadyUsedException.java
  100. 0
    0
      src/main/java/io/github/jhipster/application/web/rest/errors/package-info.java

+ 24
- 0
.editorconfig 查看文件

@@ -0,0 +1,24 @@
1
+# EditorConfig helps developers define and maintain consistent
2
+# coding styles between different editors and IDEs
3
+# editorconfig.org
4
+
5
+root = true
6
+
7
+[*]
8
+
9
+# Change these settings to your own preference
10
+indent_style = space
11
+indent_size = 4
12
+
13
+# We recommend you to keep these unchanged
14
+end_of_line = lf
15
+charset = utf-8
16
+trim_trailing_whitespace = true
17
+insert_final_newline = true
18
+
19
+[*.md]
20
+trim_trailing_whitespace = false
21
+
22
+[{package,bower}.json]
23
+indent_style = space
24
+indent_size = 2

+ 149
- 0
.gitattributes 查看文件

@@ -0,0 +1,149 @@
1
+# This file is inspired by https://github.com/alexkaratarakis/gitattributes
2
+#
3
+# Auto detect text files and perform LF normalization
4
+# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/
5
+* text=auto
6
+
7
+# The above will handle all files NOT found below
8
+# These files are text and should be normalized (Convert crlf => lf)
9
+
10
+*.bat           text eol=crlf
11
+*.coffee        text
12
+*.css           text
13
+*.cql           text
14
+*.df            text
15
+*.ejs           text
16
+*.html          text
17
+*.java          text
18
+*.js            text
19
+*.json          text
20
+*.less          text
21
+*.properties    text
22
+*.sass          text
23
+*.scss          text
24
+*.sh            text eol=lf
25
+*.sql           text
26
+*.txt           text
27
+*.ts            text
28
+*.xml           text
29
+*.yaml          text
30
+*.yml           text
31
+
32
+# Documents
33
+*.doc           diff=astextplain
34
+*.DOC           diff=astextplain
35
+*.docx          diff=astextplain
36
+*.DOCX          diff=astextplain
37
+*.dot           diff=astextplain
38
+*.DOT           diff=astextplain
39
+*.pdf           diff=astextplain
40
+*.PDF           diff=astextplain
41
+*.rtf           diff=astextplain
42
+*.RTF           diff=astextplain
43
+*.markdown      text
44
+*.md            text
45
+*.adoc          text
46
+*.textile       text
47
+*.mustache      text
48
+*.csv           text
49
+*.tab           text
50
+*.tsv           text
51
+*.txt           text
52
+AUTHORS         text
53
+CHANGELOG       text
54
+CHANGES         text
55
+CONTRIBUTING    text
56
+COPYING         text
57
+copyright       text
58
+*COPYRIGHT*     text
59
+INSTALL         text
60
+license         text
61
+LICENSE         text
62
+NEWS            text
63
+readme          text
64
+*README*        text
65
+TODO            text
66
+
67
+# Graphics
68
+*.png           binary
69
+*.jpg           binary
70
+*.jpeg          binary
71
+*.gif           binary
72
+*.tif           binary
73
+*.tiff          binary
74
+*.ico           binary
75
+# SVG treated as an asset (binary) by default. If you want to treat it as text,
76
+# comment-out the following line and uncomment the line after.
77
+*.svg           binary
78
+#*.svg          text
79
+*.eps           binary
80
+
81
+# These files are binary and should be left untouched
82
+# (binary is a macro for -text -diff)
83
+*.class         binary
84
+*.jar           binary
85
+*.war           binary
86
+
87
+## LINTERS
88
+.csslintrc      text
89
+.eslintrc       text
90
+.jscsrc         text
91
+.jshintrc       text
92
+.jshintignore   text
93
+.stylelintrc    text
94
+
95
+## CONFIGS
96
+*.bowerrc       text
97
+*.conf          text
98
+*.config        text
99
+.editorconfig   text
100
+.gitattributes  text
101
+.gitconfig      text
102
+.gitignore      text
103
+.htaccess       text
104
+*.npmignore     text
105
+
106
+## HEROKU
107
+Procfile        text
108
+.slugignore     text
109
+
110
+## AUDIO
111
+*.kar           binary
112
+*.m4a           binary
113
+*.mid           binary
114
+*.midi          binary
115
+*.mp3           binary
116
+*.ogg           binary
117
+*.ra            binary
118
+
119
+## VIDEO
120
+*.3gpp          binary
121
+*.3gp           binary
122
+*.as            binary
123
+*.asf           binary
124
+*.asx           binary
125
+*.fla           binary
126
+*.flv           binary
127
+*.m4v           binary
128
+*.mng           binary
129
+*.mov           binary
130
+*.mp4           binary
131
+*.mpeg          binary
132
+*.mpg           binary
133
+*.swc           binary
134
+*.swf           binary
135
+*.webm          binary
136
+
137
+## ARCHIVES
138
+*.7z            binary
139
+*.gz            binary
140
+*.rar           binary
141
+*.tar           binary
142
+*.zip           binary
143
+
144
+## FONTS
145
+*.ttf           binary
146
+*.eot           binary
147
+*.otf           binary
148
+*.woff          binary
149
+*.woff2         binary

+ 144
- 0
.gitignore 查看文件

@@ -0,0 +1,144 @@
1
+######################
2
+# Project Specific
3
+######################
4
+/target/www/**
5
+/src/test/javascript/coverage/
6
+
7
+######################
8
+# Node
9
+######################
10
+/node/
11
+node_tmp/
12
+node_modules/
13
+npm-debug.log.*
14
+/.awcache/*
15
+/.cache-loader/*
16
+
17
+######################
18
+# SASS
19
+######################
20
+.sass-cache/
21
+
22
+######################
23
+# Eclipse
24
+######################
25
+*.pydevproject
26
+.project
27
+.metadata
28
+tmp/
29
+tmp/**/*
30
+*.tmp
31
+*.bak
32
+*.swp
33
+*~.nib
34
+local.properties
35
+.classpath
36
+.settings/
37
+.loadpath
38
+.factorypath
39
+/src/main/resources/rebel.xml
40
+
41
+# External tool builders
42
+.externalToolBuilders/**
43
+
44
+# Locally stored "Eclipse launch configurations"
45
+*.launch
46
+
47
+# CDT-specific
48
+.cproject
49
+
50
+# PDT-specific
51
+.buildpath
52
+
53
+######################
54
+# Intellij
55
+######################
56
+.idea/
57
+*.iml
58
+*.iws
59
+*.ipr
60
+*.ids
61
+*.orig
62
+classes/
63
+out/
64
+
65
+######################
66
+# Visual Studio Code
67
+######################
68
+.vscode/
69
+
70
+######################
71
+# Maven
72
+######################
73
+/log/
74
+/target/
75
+
76
+######################
77
+# Gradle
78
+######################
79
+.gradle/
80
+/build/
81
+
82
+######################
83
+# Package Files
84
+######################
85
+*.jar
86
+*.war
87
+*.ear
88
+*.db
89
+
90
+######################
91
+# Windows
92
+######################
93
+# Windows image file caches
94
+Thumbs.db
95
+
96
+# Folder config file
97
+Desktop.ini
98
+
99
+######################
100
+# Mac OSX
101
+######################
102
+.DS_Store
103
+.svn
104
+
105
+# Thumbnails
106
+._*
107
+
108
+# Files that might appear on external disk
109
+.Spotlight-V100
110
+.Trashes
111
+
112
+######################
113
+# Directories
114
+######################
115
+/bin/
116
+/deploy/
117
+
118
+######################
119
+# Logs
120
+######################
121
+*.log*
122
+
123
+######################
124
+# Others
125
+######################
126
+*.class
127
+*.*~
128
+*~
129
+.merge_file*
130
+
131
+######################
132
+# Gradle Wrapper
133
+######################
134
+!gradle/wrapper/gradle-wrapper.jar
135
+
136
+######################
137
+# Maven Wrapper
138
+######################
139
+!.mvn/wrapper/maven-wrapper.jar
140
+
141
+######################
142
+# ESLint
143
+######################
144
+.eslintcache

+ 5
- 0
.huskyrc 查看文件

@@ -0,0 +1,5 @@
1
+{
2
+  "hooks": {
3
+     "pre-commit": "lint-staged"
4
+  }
5
+}

+ 110
- 0
.mvn/wrapper/MavenWrapperDownloader.java 查看文件

@@ -0,0 +1,110 @@
1
+/*
2
+Licensed to the Apache Software Foundation (ASF) under one
3
+or more contributor license agreements.  See the NOTICE file
4
+distributed with this work for additional information
5
+regarding copyright ownership.  The ASF licenses this file
6
+to you under the Apache License, Version 2.0 (the
7
+"License"); you may not use this file except in compliance
8
+with the License.  You may obtain a copy of the License at
9
+
10
+  http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+Unless required by applicable law or agreed to in writing,
13
+software distributed under the License is distributed on an
14
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+KIND, either express or implied.  See the License for the
16
+specific language governing permissions and limitations
17
+under the License.
18
+*/
19
+
20
+import java.net.*;
21
+import java.io.*;
22
+import java.nio.channels.*;
23
+import java.util.Properties;
24
+
25
+public class MavenWrapperDownloader {
26
+
27
+    /**
28
+     * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
29
+     */
30
+    private static final String DEFAULT_DOWNLOAD_URL =
31
+            "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";
32
+
33
+    /**
34
+     * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
35
+     * use instead of the default one.
36
+     */
37
+    private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
38
+            ".mvn/wrapper/maven-wrapper.properties";
39
+
40
+    /**
41
+     * Path where the maven-wrapper.jar will be saved to.
42
+     */
43
+    private static final String MAVEN_WRAPPER_JAR_PATH =
44
+            ".mvn/wrapper/maven-wrapper.jar";
45
+
46
+    /**
47
+     * Name of the property which should be used to override the default download url for the wrapper.
48
+     */
49
+    private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
50
+
51
+    public static void main(String args[]) {
52
+        System.out.println("- Downloader started");
53
+        File baseDirectory = new File(args[0]);
54
+        System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
55
+
56
+        // If the maven-wrapper.properties exists, read it and check if it contains a custom
57
+        // wrapperUrl parameter.
58
+        File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
59
+        String url = DEFAULT_DOWNLOAD_URL;
60
+        if (mavenWrapperPropertyFile.exists()) {
61
+            FileInputStream mavenWrapperPropertyFileInputStream = null;
62
+            try {
63
+                mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
64
+                Properties mavenWrapperProperties = new Properties();
65
+                mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
66
+                url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
67
+            } catch (IOException e) {
68
+                System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
69
+            } finally {
70
+                try {
71
+                    if (mavenWrapperPropertyFileInputStream != null) {
72
+                        mavenWrapperPropertyFileInputStream.close();
73
+                    }
74
+                } catch (IOException e) {
75
+                    // Ignore ...
76
+                }
77
+            }
78
+        }
79
+        System.out.println("- Downloading from: : " + url);
80
+
81
+        File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
82
+        if (!outputFile.getParentFile().exists()) {
83
+            if (!outputFile.getParentFile().mkdirs()) {
84
+                System.out.println(
85
+                        "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
86
+            }
87
+        }
88
+        System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
89
+        try {
90
+            downloadFileFromURL(url, outputFile);
91
+            System.out.println("Done");
92
+            System.exit(0);
93
+        } catch (Throwable e) {
94
+            System.out.println("- Error downloading");
95
+            e.printStackTrace();
96
+            System.exit(1);
97
+        }
98
+    }
99
+
100
+    private static void downloadFileFromURL(String urlString, File destination) throws Exception {
101
+        URL website = new URL(urlString);
102
+        ReadableByteChannel rbc;
103
+        rbc = Channels.newChannel(website.openStream());
104
+        FileOutputStream fos = new FileOutputStream(destination);
105
+        fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
106
+        fos.close();
107
+        rbc.close();
108
+    }
109
+
110
+}

二進制
.mvn/wrapper/maven-wrapper.jar 查看文件


+ 1
- 0
.mvn/wrapper/maven-wrapper.properties 查看文件

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

+ 2
- 0
.prettierignore 查看文件

@@ -0,0 +1,2 @@
1
+node_modules
2
+target

+ 12
- 0
.prettierrc 查看文件

@@ -0,0 +1,12 @@
1
+# Prettier configuration
2
+
3
+printWidth: 140
4
+singleQuote: true
5
+tabWidth: 4
6
+useTabs: false
7
+
8
+# js and ts rules:
9
+arrowParens: avoid
10
+
11
+# jsx and tsx rules:
12
+jsxBracketSameLine: false

+ 36
- 0
.yo-rc.json 查看文件

@@ -0,0 +1,36 @@
1
+{
2
+  "generator-jhipster": {
3
+    "applicationType": "monolith",
4
+    "gitCompany": "",
5
+    "baseName": "privyBlog",
6
+    "packageName": "io.github.jhipster.application",
7
+    "packageFolder": "io/github/jhipster/application",
8
+    "serverPort": 8085,
9
+    "serviceDiscoveryType": false,
10
+    "authenticationType": "jwt",
11
+    "uaaBaseName": "../uaa",
12
+    "cacheProvider": "ehcache",
13
+    "enableHibernateCache": true,
14
+    "websocket": "spring-websocket",
15
+    "databaseType": "sql",
16
+    "devDatabaseType": "h2Disk",
17
+    "prodDatabaseType": "postgresql",
18
+    "searchEngine": "elasticsearch",
19
+    "enableSwaggerCodegen": false,
20
+    "messageBroker": "",
21
+    "buildTool": "maven",
22
+    "useSass": false,
23
+    "clientPackageManager": "npm",
24
+    "testFrameworks": [],
25
+    "enableTranslation": false,
26
+    "nativeLanguage": "en",
27
+    "languages": [
28
+      "en"
29
+    ],
30
+    "clientFramework": "angularX",
31
+    "jhiPrefix": "jhi",
32
+    "jhipsterVersion": "5.7.0",
33
+    "jwtSecretKey": "ZmNiNTBmN2EyM2JjMWQ4MmIzYjM2MTEyYTdiNmM5MDUwNjE4YmRlY2EwMWMyZjExOTcyNjdkZDk4YTQ0YzcyMWI4Y2Q2ZWFlZDFjZDgyNzRjMDRlNWZlYjU0ODYxOTJlNDc4OWY0YmRlMTk4YmYzY2NkY2VmNzQxMmNlOTBlMDQ=",
34
+    "otherModules": []
35
+  }
36
+}

+ 105
- 0
README.md 查看文件

@@ -0,0 +1,105 @@
1
+# privyBlog
2
+This application was generated using JHipster 5.7.0, you can find documentation and help at [https://www.jhipster.tech/documentation-archive/v5.7.0](https://www.jhipster.tech/documentation-archive/v5.7.0).
3
+
4
+## Development
5
+
6
+To start your application in the dev profile, simply run:
7
+
8
+and start Kafka first??
9
+docker-compose -f src/main/docker/kafka.yml up -d
10
+
11
+    ./mvnw
12
+
13
+
14
+For further instructions on how to develop with JHipster, have a look at [Using JHipster in development][].
15
+
16
+### Using angular-cli
17
+
18
+You can also use [Angular CLI][] to generate some custom client code.
19
+
20
+For example, the following command:
21
+
22
+    ng generate component my-component
23
+
24
+will generate few files:
25
+
26
+    create src/main/webapp/app/my-component/my-component.component.html
27
+    create src/main/webapp/app/my-component/my-component.component.ts
28
+    update src/main/webapp/app/app.module.ts
29
+
30
+
31
+## Building for production
32
+
33
+To optimize the privyBlog application for production, run:
34
+
35
+    ./mvnw -Pprod clean package
36
+
37
+To ensure everything worked, run:
38
+
39
+    java -jar target/*.war
40
+
41
+
42
+Refer to [Using JHipster in production][] for more details.
43
+
44
+## Testing
45
+
46
+To launch your application's tests, run:
47
+
48
+    ./mvnw clean test
49
+
50
+For more information, refer to the [Running tests page][].
51
+
52
+### Code quality
53
+
54
+Sonar is used to analyse code quality. You can start a local Sonar server (accessible on http://localhost:9001) with:
55
+
56
+```
57
+docker-compose -f src/main/docker/sonar.yml up -d
58
+```
59
+
60
+Then, run a Sonar analysis:
61
+
62
+```
63
+./mvnw -Pprod clean test sonar:sonar
64
+```
65
+
66
+For more information, refer to the [Code quality page][].
67
+
68
+## Using Docker to simplify development (optional)
69
+
70
+You can use Docker to improve your JHipster development experience. A number of docker-compose configuration are available in the [src/main/docker](src/main/docker) folder to launch required third party services.
71
+
72
+For example, to start a postgresql database in a docker container, run:
73
+
74
+    docker-compose -f src/main/docker/postgresql.yml up -d
75
+
76
+To stop it and remove the container, run:
77
+
78
+    docker-compose -f src/main/docker/postgresql.yml down
79
+
80
+You can also fully dockerize your application and all the services that it depends on.
81
+To achieve this, first build a docker image of your app by running:
82
+
83
+    ./mvnw package -Pprod jib:dockerBuild
84
+
85
+Then run:
86
+
87
+    docker-compose -f src/main/docker/app.yml up -d
88
+
89
+For more information refer to [Using Docker and Docker-Compose][], this page also contains information on the docker-compose sub-generator (`jhipster docker-compose`), which is able to generate docker configurations for one or several JHipster applications.
90
+
91
+## Continuous Integration (optional)
92
+
93
+To configure CI for your project, run the ci-cd sub-generator (`jhipster ci-cd`), this will let you generate configuration files for a number of Continuous Integration systems. Consult the [Setting up Continuous Integration][] page for more information.
94
+
95
+[JHipster Homepage and latest documentation]: https://www.jhipster.tech
96
+[JHipster 5.7.0 archive]: https://www.jhipster.tech/documentation-archive/v5.7.0
97
+
98
+[Using JHipster in development]: https://www.jhipster.tech/documentation-archive/v5.7.0/development/
99
+[Using Docker and Docker-Compose]: https://www.jhipster.tech/documentation-archive/v5.7.0/docker-compose
100
+[Using JHipster in production]: https://www.jhipster.tech/documentation-archive/v5.7.0/production/
101
+[Running tests page]: https://www.jhipster.tech/documentation-archive/v5.7.0/running-tests/
102
+[Code quality page]: https://www.jhipster.tech/documentation-archive/v5.7.0/code-quality/
103
+[Setting up Continuous Integration]: https://www.jhipster.tech/documentation-archive/v5.7.0/setting-up-ci/
104
+
105
+

+ 39
- 0
angular.json 查看文件

@@ -0,0 +1,39 @@
1
+{
2
+  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3
+  "version": 1,
4
+  "newProjectRoot": "projects",
5
+  "projects": {
6
+    "privy-blog": {
7
+      "root": "",
8
+      "sourceRoot": "src/main/webapp",
9
+      "projectType": "application",
10
+      "architect": {}
11
+    }
12
+  },
13
+  "defaultProject": "privy-blog",
14
+  "cli": {
15
+    "packageManager": "npm"
16
+  },
17
+  "schematics": {
18
+    "@schematics/angular:component": {
19
+      "inlineStyle": true,
20
+      "inlineTemplate": false,
21
+      "spec": false,
22
+      "prefix": "jhi",
23
+      "styleExt": "css"
24
+    },
25
+    "@schematics/angular:directive": {
26
+      "spec": false,
27
+      "prefix": "jhi"
28
+    },
29
+    "@schematics/angular:guard": {
30
+      "spec": false
31
+    },
32
+    "@schematics/angular:pipe": {
33
+      "spec": false
34
+    },
35
+    "@schematics/angular:service": {
36
+      "spec": false
37
+    }
38
+  }
39
+}

+ 286
- 0
mvnw 查看文件

@@ -0,0 +1,286 @@
1
+#!/bin/sh
2
+# ----------------------------------------------------------------------------
3
+# Licensed to the Apache Software Foundation (ASF) under one
4
+# or more contributor license agreements.  See the NOTICE file
5
+# distributed with this work for additional information
6
+# regarding copyright ownership.  The ASF licenses this file
7
+# to you under the Apache License, Version 2.0 (the
8
+# "License"); you may not use this file except in compliance
9
+# with the License.  You may obtain a copy of the License at
10
+#
11
+#    http://www.apache.org/licenses/LICENSE-2.0
12
+#
13
+# Unless required by applicable law or agreed to in writing,
14
+# software distributed under the License is distributed on an
15
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+# KIND, either express or implied.  See the License for the
17
+# specific language governing permissions and limitations
18
+# under the License.
19
+# ----------------------------------------------------------------------------
20
+
21
+# ----------------------------------------------------------------------------
22
+# Maven2 Start Up Batch script
23
+#
24
+# Required ENV vars:
25
+# ------------------
26
+#   JAVA_HOME - location of a JDK home dir
27
+#
28
+# Optional ENV vars
29
+# -----------------
30
+#   M2_HOME - location of maven2's installed home dir
31
+#   MAVEN_OPTS - parameters passed to the Java VM when running Maven
32
+#     e.g. to debug Maven itself, use
33
+#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34
+#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35
+# ----------------------------------------------------------------------------
36
+
37
+if [ -z "$MAVEN_SKIP_RC" ] ; then
38
+
39
+  if [ -f /etc/mavenrc ] ; then
40
+    . /etc/mavenrc
41
+  fi
42
+
43
+  if [ -f "$HOME/.mavenrc" ] ; then
44
+    . "$HOME/.mavenrc"
45
+  fi
46
+
47
+fi
48
+
49
+# OS specific support.  $var _must_ be set to either true or false.
50
+cygwin=false;
51
+darwin=false;
52
+mingw=false
53
+case "`uname`" in
54
+  CYGWIN*) cygwin=true ;;
55
+  MINGW*) mingw=true;;
56
+  Darwin*) darwin=true
57
+    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58
+    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59
+    if [ -z "$JAVA_HOME" ]; then
60
+      if [ -x "/usr/libexec/java_home" ]; then
61
+        export JAVA_HOME="`/usr/libexec/java_home`"
62
+      else
63
+        export JAVA_HOME="/Library/Java/Home"
64
+      fi
65
+    fi
66
+    ;;
67
+esac
68
+
69
+if [ -z "$JAVA_HOME" ] ; then
70
+  if [ -r /etc/gentoo-release ] ; then
71
+    JAVA_HOME=`java-config --jre-home`
72
+  fi
73
+fi
74
+
75
+if [ -z "$M2_HOME" ] ; then
76
+  ## resolve links - $0 may be a link to maven's home
77
+  PRG="$0"
78
+
79
+  # need this for relative symlinks
80
+  while [ -h "$PRG" ] ; do
81
+    ls=`ls -ld "$PRG"`
82
+    link=`expr "$ls" : '.*-> \(.*\)$'`
83
+    if expr "$link" : '/.*' > /dev/null; then
84
+      PRG="$link"
85
+    else
86
+      PRG="`dirname "$PRG"`/$link"
87
+    fi
88
+  done
89
+
90
+  saveddir=`pwd`
91
+
92
+  M2_HOME=`dirname "$PRG"`/..
93
+
94
+  # make it fully qualified
95
+  M2_HOME=`cd "$M2_HOME" && pwd`
96
+
97
+  cd "$saveddir"
98
+  # echo Using m2 at $M2_HOME
99
+fi
100
+
101
+# For Cygwin, ensure paths are in UNIX format before anything is touched
102
+if $cygwin ; then
103
+  [ -n "$M2_HOME" ] &&
104
+    M2_HOME=`cygpath --unix "$M2_HOME"`
105
+  [ -n "$JAVA_HOME" ] &&
106
+    JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107
+  [ -n "$CLASSPATH" ] &&
108
+    CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109
+fi
110
+
111
+# For Mingw, ensure paths are in UNIX format before anything is touched
112
+if $mingw ; then
113
+  [ -n "$M2_HOME" ] &&
114
+    M2_HOME="`(cd "$M2_HOME"; pwd)`"
115
+  [ -n "$JAVA_HOME" ] &&
116
+    JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117
+  # TODO classpath?
118
+fi
119
+
120
+if [ -z "$JAVA_HOME" ]; then
121
+  javaExecutable="`which javac`"
122
+  if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123
+    # readlink(1) is not available as standard on Solaris 10.
124
+    readLink=`which readlink`
125
+    if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126
+      if $darwin ; then
127
+        javaHome="`dirname \"$javaExecutable\"`"
128
+        javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129
+      else
130
+        javaExecutable="`readlink -f \"$javaExecutable\"`"
131
+      fi
132
+      javaHome="`dirname \"$javaExecutable\"`"
133
+      javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134
+      JAVA_HOME="$javaHome"
135
+      export JAVA_HOME
136
+    fi
137
+  fi
138
+fi
139
+
140
+if [ -z "$JAVACMD" ] ; then
141
+  if [ -n "$JAVA_HOME"  ] ; then
142
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143
+      # IBM's JDK on AIX uses strange locations for the executables
144
+      JAVACMD="$JAVA_HOME/jre/sh/java"
145
+    else
146
+      JAVACMD="$JAVA_HOME/bin/java"
147
+    fi
148
+  else
149
+    JAVACMD="`which java`"
150
+  fi
151
+fi
152
+
153
+if [ ! -x "$JAVACMD" ] ; then
154
+  echo "Error: JAVA_HOME is not defined correctly." >&2
155
+  echo "  We cannot execute $JAVACMD" >&2
156
+  exit 1
157
+fi
158
+
159
+if [ -z "$JAVA_HOME" ] ; then
160
+  echo "Warning: JAVA_HOME environment variable is not set."
161
+fi
162
+
163
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164
+
165
+# traverses directory structure from process work directory to filesystem root
166
+# first directory with .mvn subdirectory is considered project base directory
167
+find_maven_basedir() {
168
+
169
+  if [ -z "$1" ]
170
+  then
171
+    echo "Path not specified to find_maven_basedir"
172
+    return 1
173
+  fi
174
+
175
+  basedir="$1"
176
+  wdir="$1"
177
+  while [ "$wdir" != '/' ] ; do
178
+    if [ -d "$wdir"/.mvn ] ; then
179
+      basedir=$wdir
180
+      break
181
+    fi
182
+    # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183
+    if [ -d "${wdir}" ]; then
184
+      wdir=`cd "$wdir/.."; pwd`
185
+    fi
186
+    # end of workaround
187
+  done
188
+  echo "${basedir}"
189
+}
190
+
191
+# concatenates all lines of a file
192
+concat_lines() {
193
+  if [ -f "$1" ]; then
194
+    echo "$(tr -s '\n' ' ' < "$1")"
195
+  fi
196
+}
197
+
198
+BASE_DIR=`find_maven_basedir "$(pwd)"`
199
+if [ -z "$BASE_DIR" ]; then
200
+  exit 1;
201
+fi
202
+
203
+##########################################################################################
204
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
205
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
206
+##########################################################################################
207
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
208
+    if [ "$MVNW_VERBOSE" = true ]; then
209
+      echo "Found .mvn/wrapper/maven-wrapper.jar"
210
+    fi
211
+else
212
+    if [ "$MVNW_VERBOSE" = true ]; then
213
+      echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
214
+    fi
215
+    jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
216
+    while IFS="=" read key value; do
217
+      case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
218
+      esac
219
+    done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
220
+    if [ "$MVNW_VERBOSE" = true ]; then
221
+      echo "Downloading from: $jarUrl"
222
+    fi
223
+    wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
224
+
225
+    if command -v wget > /dev/null; then
226
+        if [ "$MVNW_VERBOSE" = true ]; then
227
+          echo "Found wget ... using wget"
228
+        fi
229
+        wget "$jarUrl" -O "$wrapperJarPath"
230
+    elif command -v curl > /dev/null; then
231
+        if [ "$MVNW_VERBOSE" = true ]; then
232
+          echo "Found curl ... using curl"
233
+        fi
234
+        curl -o "$wrapperJarPath" "$jarUrl"
235
+    else
236
+        if [ "$MVNW_VERBOSE" = true ]; then
237
+          echo "Falling back to using Java to download"
238
+        fi
239
+        javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
240
+        if [ -e "$javaClass" ]; then
241
+            if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
242
+                if [ "$MVNW_VERBOSE" = true ]; then
243
+                  echo " - Compiling MavenWrapperDownloader.java ..."
244
+                fi
245
+                # Compiling the Java class
246
+                ("$JAVA_HOME/bin/javac" "$javaClass")
247
+            fi
248
+            if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
249
+                # Running the downloader
250
+                if [ "$MVNW_VERBOSE" = true ]; then
251
+                  echo " - Running MavenWrapperDownloader.java ..."
252
+                fi
253
+                ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
254
+            fi
255
+        fi
256
+    fi
257
+fi
258
+##########################################################################################
259
+# End of extension
260
+##########################################################################################
261
+
262
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
263
+if [ "$MVNW_VERBOSE" = true ]; then
264
+  echo $MAVEN_PROJECTBASEDIR
265
+fi
266
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
267
+
268
+# For Cygwin, switch paths to Windows format before running java
269
+if $cygwin; then
270
+  [ -n "$M2_HOME" ] &&
271
+    M2_HOME=`cygpath --path --windows "$M2_HOME"`
272
+  [ -n "$JAVA_HOME" ] &&
273
+    JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
274
+  [ -n "$CLASSPATH" ] &&
275
+    CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
276
+  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
277
+    MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
278
+fi
279
+
280
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
281
+
282
+exec "$JAVACMD" \
283
+  $MAVEN_OPTS \
284
+  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
285
+  "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
286
+  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

+ 161
- 0
mvnw.cmd 查看文件

@@ -0,0 +1,161 @@
1
+@REM ----------------------------------------------------------------------------
2
+@REM Licensed to the Apache Software Foundation (ASF) under one
3
+@REM or more contributor license agreements.  See the NOTICE file
4
+@REM distributed with this work for additional information
5
+@REM regarding copyright ownership.  The ASF licenses this file
6
+@REM to you under the Apache License, Version 2.0 (the
7
+@REM "License"); you may not use this file except in compliance
8
+@REM with the License.  You may obtain a copy of the License at
9
+@REM
10
+@REM    http://www.apache.org/licenses/LICENSE-2.0
11
+@REM
12
+@REM Unless required by applicable law or agreed to in writing,
13
+@REM software distributed under the License is distributed on an
14
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+@REM KIND, either express or implied.  See the License for the
16
+@REM specific language governing permissions and limitations
17
+@REM under the License.
18
+@REM ----------------------------------------------------------------------------
19
+
20
+@REM ----------------------------------------------------------------------------
21
+@REM Maven2 Start Up Batch script
22
+@REM
23
+@REM Required ENV vars:
24
+@REM JAVA_HOME - location of a JDK home dir
25
+@REM
26
+@REM Optional ENV vars
27
+@REM M2_HOME - location of maven2's installed home dir
28
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31
+@REM     e.g. to debug Maven itself, use
32
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34
+@REM ----------------------------------------------------------------------------
35
+
36
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37
+@echo off
38
+@REM set title of command window
39
+title %0
40
+@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
41
+@if "%MAVEN_BATCH_ECHO%" == "on"  echo %MAVEN_BATCH_ECHO%
42
+
43
+@REM set %HOME% to equivalent of $HOME
44
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
45
+
46
+@REM Execute a user defined script before this one
47
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
48
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
49
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
50
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
51
+:skipRcPre
52
+
53
+@setlocal
54
+
55
+set ERROR_CODE=0
56
+
57
+@REM To isolate internal variables from possible post scripts, we use another setlocal
58
+@setlocal
59
+
60
+@REM ==== START VALIDATION ====
61
+if not "%JAVA_HOME%" == "" goto OkJHome
62
+
63
+echo.
64
+echo Error: JAVA_HOME not found in your environment. >&2
65
+echo Please set the JAVA_HOME variable in your environment to match the >&2
66
+echo location of your Java installation. >&2
67
+echo.
68
+goto error
69
+
70
+:OkJHome
71
+if exist "%JAVA_HOME%\bin\java.exe" goto init
72
+
73
+echo.
74
+echo Error: JAVA_HOME is set to an invalid directory. >&2
75
+echo JAVA_HOME = "%JAVA_HOME%" >&2
76
+echo Please set the JAVA_HOME variable in your environment to match the >&2
77
+echo location of your Java installation. >&2
78
+echo.
79
+goto error
80
+
81
+@REM ==== END VALIDATION ====
82
+
83
+:init
84
+
85
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86
+@REM Fallback to current working directory if not found.
87
+
88
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90
+
91
+set EXEC_DIR=%CD%
92
+set WDIR=%EXEC_DIR%
93
+:findBaseDir
94
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
95
+cd ..
96
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
97
+set WDIR=%CD%
98
+goto findBaseDir
99
+
100
+:baseDirFound
101
+set MAVEN_PROJECTBASEDIR=%WDIR%
102
+cd "%EXEC_DIR%"
103
+goto endDetectBaseDir
104
+
105
+:baseDirNotFound
106
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107
+cd "%EXEC_DIR%"
108
+
109
+:endDetectBaseDir
110
+
111
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112
+
113
+@setlocal EnableExtensions EnableDelayedExpansion
114
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116
+
117
+:endReadAdditionalConfig
118
+
119
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
121
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
122
+
123
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
124
+FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
125
+	IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 
126
+)
127
+
128
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
129
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
130
+if exist %WRAPPER_JAR% (
131
+    echo Found %WRAPPER_JAR%
132
+) else (
133
+    echo Couldn't find %WRAPPER_JAR%, downloading it ...
134
+	echo Downloading from: %DOWNLOAD_URL%
135
+    powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
136
+    echo Finished downloading %WRAPPER_JAR%
137
+)
138
+@REM End of extension
139
+
140
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
141
+if ERRORLEVEL 1 goto error
142
+goto end
143
+
144
+:error
145
+set ERROR_CODE=1
146
+
147
+:end
148
+@endlocal & set ERROR_CODE=%ERROR_CODE%
149
+
150
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
151
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
152
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
153
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
154
+:skipRcPost
155
+
156
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
157
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
158
+
159
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
160
+
161
+exit /B %ERROR_CODE%

+ 19023
- 0
package-lock.json
文件差異過大導致無法顯示
查看文件


+ 126
- 0
package.json 查看文件

@@ -0,0 +1,126 @@
1
+{
2
+  "name": "privy-blog",
3
+  "version": "0.0.0",
4
+  "description": "Description for privyBlog",
5
+  "private": true,
6
+  "license": "UNLICENSED",
7
+  "cacheDirectories": [
8
+    "node_modules"
9
+  ],
10
+  "dependencies": {
11
+    "@angular/common": "7.0.0",
12
+    "@angular/compiler": "7.0.0",
13
+    "@angular/core": "7.0.0",
14
+    "@angular/forms": "7.0.0",
15
+    "@angular/platform-browser": "7.0.0",
16
+    "@angular/platform-browser-dynamic": "7.0.0",
17
+    "@angular/router": "7.0.0",
18
+    "@fortawesome/angular-fontawesome": "0.3.0",
19
+    "@fortawesome/fontawesome-svg-core": "1.2.8",
20
+    "@fortawesome/free-solid-svg-icons": "5.5.0",
21
+    "@ng-bootstrap/ng-bootstrap": "4.0.0",
22
+    "bootstrap": "4.1.3",
23
+    "core-js": "2.5.7",
24
+    "moment": "2.22.2",
25
+    "ng-jhipster": "0.5.6",
26
+    "ngx-cookie": "2.0.1",
27
+    "ngx-infinite-scroll": "6.0.1",
28
+    "ngx-webstorage": "2.0.1",
29
+    "reflect-metadata": "0.1.12",
30
+    "rxjs": "6.3.3",
31
+    "swagger-ui": "2.2.10",
32
+    "sockjs-client": "1.1.4",
33
+    "webstomp-client": "1.2.0",
34
+    "tslib": "1.9.3",
35
+    "zone.js": "0.8.26"
36
+  },
37
+  "devDependencies": {
38
+    "@angular/cli": "7.0.2",
39
+    "@angular/compiler-cli": "7.0.0",
40
+    "@ngtools/webpack": "7.0.2",
41
+    "@types/jest": "23.3.5",
42
+    "@types/node": "9.4.7",
43
+    "angular-router-loader": "0.8.5",
44
+    "angular2-template-loader": "0.6.2",
45
+    "autoprefixer": "9.2.0",
46
+    "browser-sync": "2.26.3",
47
+    "browser-sync-webpack-plugin": "2.2.2",
48
+    "cache-loader": "1.2.2",
49
+    "codelyzer": "4.5.0",
50
+    "copy-webpack-plugin": "4.5.1",
51
+    "css-loader": "0.28.10",
52
+    "file-loader": "1.1.11",
53
+    "fork-ts-checker-webpack-plugin": "0.4.10",
54
+    "friendly-errors-webpack-plugin": "1.7.0",
55
+    "generator-jhipster": "5.7.0",
56
+    "html-loader": "0.5.5",
57
+    "html-webpack-plugin": "3.2.0",
58
+    "husky": "1.1.0",
59
+    "jest": "23.6.0",
60
+    "jest-junit": "5.1.0",
61
+    "jest-preset-angular": "6.0.1",
62
+    "jest-sonar-reporter": "2.0.0",
63
+    "lint-staged": "7.3.0",
64
+    "mini-css-extract-plugin": "0.4.2",
65
+    "moment-locales-webpack-plugin": "1.0.5",
66
+    "optimize-css-assets-webpack-plugin": "5.0.1",
67
+    "prettier": "1.14.3",
68
+    "rimraf": "2.6.1",
69
+    "simple-progress-webpack-plugin": "1.1.2",
70
+    "style-loader": "0.20.3",
71
+    "terser-webpack-plugin": "1.0.0",
72
+    "thread-loader": "1.1.5",
73
+    "to-string-loader": "1.1.5",
74
+    "ts-loader": "4.5.0",
75
+    "tslint": "5.11.0",
76
+    "tslint-config-prettier": "1.15.0",
77
+    "tslint-loader": "3.6.0",
78
+    "typescript": "3.1.3",
79
+    "postcss-loader": "2.1.6",
80
+    "xml2js": "0.4.19",
81
+    "webpack": "4.25.1",
82
+    "webpack-cli": "3.1.2",
83
+    "webpack-dev-server": "3.1.10",
84
+    "webpack-merge": "4.1.4",
85
+    "webpack-notifier": "1.7.0",
86
+    "webpack-visualizer-plugin": "0.1.11",
87
+    "workbox-webpack-plugin": "3.6.3",
88
+    "write-file-webpack-plugin": "4.4.1"
89
+  },
90
+  "engines": {
91
+    "node": ">=8.9.0"
92
+  },
93
+  "lint-staged": {
94
+    "src/**/*.{json,ts,css,scss}": [
95
+      "prettier --write",
96
+      "git add"
97
+    ]
98
+  },
99
+  "scripts": {
100
+    "prettier:format": "prettier --write \"src/**/*.{json,ts,css,scss}\"",
101
+    "lint": "tslint --project tsconfig.json -e 'node_modules/**'",
102
+    "lint:fix": "npm run lint -- --fix",
103
+    "ngc": "ngc -p tsconfig-aot.json",
104
+    "cleanup": "rimraf target/{aot,www}",
105
+    "clean-www": "rimraf target//www/app/{src,target/}",
106
+    "start": "npm run webpack:dev",
107
+    "start-tls": "npm run webpack:dev -- --env.tls",
108
+    "serve": "npm run start",
109
+    "build": "npm run webpack:prod",
110
+    "test": "npm run lint && jest --coverage --logHeapUsage -w=2 --config src/test/javascript/jest.conf.js",
111
+    "test:watch": "npm run test -- --watch",
112
+    "webpack:dev": "npm run webpack-dev-server -- --config webpack/webpack.dev.js --inline --hot --port=9060 --watch-content-base --env.stats=minimal",
113
+    "webpack:dev-verbose": "npm run webpack-dev-server -- --config webpack/webpack.dev.js --inline --hot --port=9060 --watch-content-base --profile --progress --env.stats=normal",
114
+    "webpack:build:main": "npm run webpack -- --config webpack/webpack.dev.js --env.stats=minimal",
115
+    "webpack:build": "npm run cleanup && npm run webpack:build:main",
116
+    "webpack:prod:main": "npm run webpack -- --config webpack/webpack.prod.js --profile",
117
+    "webpack:prod": "npm run cleanup && npm run webpack:prod:main && npm run clean-www",
118
+    "webpack:test": "npm run test",
119
+    "webpack-dev-server": "node --max_old_space_size=4096 node_modules/webpack-dev-server/bin/webpack-dev-server.js",
120
+    "webpack": "node --max_old_space_size=4096 node_modules/webpack/bin/webpack.js"
121
+  },
122
+  "jestSonar": {
123
+    "reportPath": "target/test-results/jest",
124
+    "reportFile": "TESTS-results-sonar.xml"
125
+  }
126
+}

+ 1154
- 0
pom.xml
文件差異過大導致無法顯示
查看文件


+ 5
- 0
postcss.config.js 查看文件

@@ -0,0 +1,5 @@
1
+module.exports = {
2
+    plugins: [
3
+        require('autoprefixer')
4
+    ]
5
+}

+ 7
- 0
proxy.conf.json 查看文件

@@ -0,0 +1,7 @@
1
+{
2
+    "*": {
3
+        "target": "http://localhost:8085",
4
+        "secure": false,
5
+        "loglevel": "debug"
6
+    }
7
+}

+ 14
- 0
src/main/docker/.dockerignore 查看文件

@@ -0,0 +1,14 @@
1
+# https://docs.docker.com/engine/reference/builder/#dockerignore-file
2
+classes/
3
+generated-sources/
4
+generated-test-sources/
5
+h2db/
6
+maven-archiver/
7
+maven-status/
8
+reports/
9
+surefire-reports/
10
+test-classes/
11
+test-results/
12
+www/
13
+!*.jar
14
+!*.war

+ 20
- 0
src/main/docker/Dockerfile 查看文件

@@ -0,0 +1,20 @@
1
+FROM openjdk:8-jre-alpine
2
+
3
+ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \
4
+    JHIPSTER_SLEEP=0 \
5
+    JAVA_OPTS=""
6
+
7
+# Add a jhipster user to run our application so that it doesn't need to run as root
8
+RUN adduser -D -s /bin/sh jhipster
9
+WORKDIR /home/jhipster
10
+
11
+ADD entrypoint.sh entrypoint.sh
12
+RUN chmod 755 entrypoint.sh && chown jhipster:jhipster entrypoint.sh
13
+USER jhipster
14
+
15
+ENTRYPOINT ["./entrypoint.sh"]
16
+
17
+EXPOSE 8085
18
+
19
+ADD *.war app.war
20
+

+ 32
- 0
src/main/docker/app.yml 查看文件

@@ -0,0 +1,32 @@
1
+version: '2'
2
+services:
3
+    privyblog-app:
4
+        image: privyblog
5
+        environment:
6
+            - _JAVA_OPTIONS=-Xmx512m -Xms256m
7
+            - SPRING_PROFILES_ACTIVE=prod,swagger
8
+            - SPRING_DATASOURCE_URL=jdbc:postgresql://privyblog-postgresql:5432/privyBlog
9
+            - JHIPSTER_SLEEP=10 # gives time for the database to boot before the application
10
+            - SPRING_DATA_JEST_URI=http://privyblog-elasticsearch:9200
11
+            - SPRING_CLOUD_STREAM_KAFKA_BINDER_BROKERS=kafka
12
+            - SPRING_CLOUD_STREAM_KAFKA_BINDER_ZK_NODES=zookeeper
13
+        ports:
14
+            - 8085:8085
15
+    privyblog-postgresql:
16
+        extends:
17
+            file: postgresql.yml
18
+            service: privyblog-postgresql
19
+    privyblog-elasticsearch:
20
+        extends:
21
+            file: elasticsearch.yml
22
+            service: privyblog-elasticsearch
23
+    kafka:
24
+        extends:
25
+            file: kafka.yml
26
+            service: kafka
27
+        environment:
28
+            - KAFKA_ADVERTISED_HOST_NAME=kafka
29
+    zookeeper:
30
+        extends:
31
+            file: kafka.yml
32
+            service: zookeeper

+ 12
- 0
src/main/docker/elasticsearch.yml 查看文件

@@ -0,0 +1,12 @@
1
+version: '2'
2
+services:
3
+    privyblog-elasticsearch:
4
+        image: elasticsearch:5.6.5
5
+        # volumes:
6
+        #     - ~/volumes/jhipster/privyBlog/elasticsearch/:/usr/share/elasticsearch/data/
7
+        ports:
8
+            - 9200:9200
9
+            - 9300:9300
10
+        command: -Enetwork.host=0.0.0.0 -Ediscovery.type=single-node
11
+        environment:
12
+            - "ES_JAVA_OPTS=-Xms1024m -Xmx1024m"

+ 4
- 0
src/main/docker/entrypoint.sh 查看文件

@@ -0,0 +1,4 @@
1
+#!/bin/sh
2
+
3
+echo "The application will start in ${JHIPSTER_SLEEP}s..." && sleep ${JHIPSTER_SLEEP}
4
+exec java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar "${HOME}/app.war" "$@"

+ 15
- 0
src/main/docker/kafka.yml 查看文件

@@ -0,0 +1,15 @@
1
+version: '2'
2
+services:
3
+    zookeeper:
4
+        image: wurstmeister/zookeeper:3.4.6
5
+        ports:
6
+          - 2181:2181
7
+    kafka:
8
+        image: wurstmeister/kafka:1.0.0
9
+        environment:
10
+            KAFKA_ADVERTISED_HOST_NAME: localhost
11
+            KAFKA_ADVERTISED_PORT: 9092
12
+            KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
13
+            KAFKA_CREATE_TOPICS: "topic-jhipster:1:1"
14
+        ports:
15
+            - 9092:9092

+ 11
- 0
src/main/docker/postgresql.yml 查看文件

@@ -0,0 +1,11 @@
1
+version: '2'
2
+services:
3
+    privyblog-postgresql:
4
+        image: postgres:10.4
5
+        # volumes:
6
+        #     - ~/volumes/jhipster/privyBlog/postgresql/:/var/lib/postgresql/data/
7
+        environment:
8
+            - POSTGRES_USER=privyBlog
9
+            - POSTGRES_PASSWORD=
10
+        ports:
11
+            - 5432:5432

+ 7
- 0
src/main/docker/sonar.yml 查看文件

@@ -0,0 +1,7 @@
1
+version: '2'
2
+services:
3
+    privyblog-sonar:
4
+        image: sonarqube:7.1
5
+        ports:
6
+            - 9001:9000
7
+            - 9092:9092

+ 21
- 0
src/main/java/io/github/jhipster/application/ApplicationWebXml.java 查看文件

@@ -0,0 +1,21 @@
1
+package io.github.jhipster.application;
2
+
3
+import io.github.jhipster.application.config.DefaultProfileUtil;
4
+import org.springframework.boot.builder.SpringApplicationBuilder;
5
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
6
+
7
+/**
8
+ * This is a helper Java class that provides an alternative to creating a web.xml.
9
+ * This will be invoked only when the application is deployed to a Servlet container like Tomcat, JBoss etc.
10
+ */
11
+public class ApplicationWebXml extends SpringBootServletInitializer {
12
+
13
+    @Override
14
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
15
+        /**
16
+         * set a default to use when no profile is configured.
17
+         */
18
+        DefaultProfileUtil.addDefaultProfile(application.application());
19
+        return application.sources(PrivyBlogApp.class);
20
+    }
21
+}

+ 98
- 0
src/main/java/io/github/jhipster/application/PrivyBlogApp.java 查看文件

@@ -0,0 +1,98 @@
1
+package io.github.jhipster.application;
2
+
3
+import io.github.jhipster.application.config.ApplicationProperties;
4
+import io.github.jhipster.application.config.DefaultProfileUtil;
5
+
6
+import io.github.jhipster.config.JHipsterConstants;
7
+
8
+import org.apache.commons.lang3.StringUtils;
9
+import org.slf4j.Logger;
10
+import org.slf4j.LoggerFactory;
11
+import org.springframework.boot.SpringApplication;
12
+import org.springframework.boot.autoconfigure.SpringBootApplication;
13
+import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
14
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
15
+import org.springframework.core.env.Environment;
16
+
17
+import javax.annotation.PostConstruct;
18
+import java.net.InetAddress;
19
+import java.net.UnknownHostException;
20
+import java.util.Arrays;
21
+import java.util.Collection;
22
+
23
+@SpringBootApplication
24
+@EnableConfigurationProperties({LiquibaseProperties.class, ApplicationProperties.class})
25
+public class PrivyBlogApp {
26
+
27
+    private static final Logger log = LoggerFactory.getLogger(PrivyBlogApp.class);
28
+
29
+    private final Environment env;
30
+
31
+    public PrivyBlogApp(Environment env) {
32
+        this.env = env;
33
+    }
34
+
35
+    /**
36
+     * Initializes privyBlog.
37
+     * <p>
38
+     * Spring profiles can be configured with a program argument --spring.profiles.active=your-active-profile
39
+     * <p>
40
+     * You can find more information on how profiles work with JHipster on <a href="https://www.jhipster.tech/profiles/">https://www.jhipster.tech/profiles/</a>.
41
+     */
42
+    @PostConstruct
43
+    public void initApplication() {
44
+        Collection<String> activeProfiles = Arrays.asList(env.getActiveProfiles());
45
+        if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) {
46
+            log.error("You have misconfigured your application! It should not run " +
47
+                "with both the 'dev' and 'prod' profiles at the same time.");
48
+        }
49
+        if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_CLOUD)) {
50
+            log.error("You have misconfigured your application! It should not " +
51
+                "run with both the 'dev' and 'cloud' profiles at the same time.");
52
+        }
53
+    }
54
+
55
+    /**
56
+     * Main method, used to run the application.
57
+     *
58
+     * @param args the command line arguments
59
+     */
60
+    public static void main(String[] args) {
61
+        SpringApplication app = new SpringApplication(PrivyBlogApp.class);
62
+        DefaultProfileUtil.addDefaultProfile(app);
63
+        Environment env = app.run(args).getEnvironment();
64
+        logApplicationStartup(env);
65
+    }
66
+
67
+    private static void logApplicationStartup(Environment env) {
68
+        String protocol = "http";
69
+        if (env.getProperty("server.ssl.key-store") != null) {
70
+            protocol = "https";
71
+        }
72
+        String serverPort = env.getProperty("server.port");
73
+        String contextPath = env.getProperty("server.servlet.context-path");
74
+        if (StringUtils.isBlank(contextPath)) {
75
+            contextPath = "/";
76
+        }
77
+        String hostAddress = "localhost";
78
+        try {
79
+            hostAddress = InetAddress.getLocalHost().getHostAddress();
80
+        } catch (UnknownHostException e) {
81
+            log.warn("The host name could not be determined, using `localhost` as fallback");
82
+        }
83
+        log.info("\n----------------------------------------------------------\n\t" +
84
+                "Application '{}' is running! Access URLs:\n\t" +
85
+                "Local: \t\t{}://localhost:{}{}\n\t" +
86
+                "External: \t{}://{}:{}{}\n\t" +
87
+                "Profile(s): \t{}\n----------------------------------------------------------",
88
+            env.getProperty("spring.application.name"),
89
+            protocol,
90
+            serverPort,
91
+            contextPath,
92
+            protocol,
93
+            hostAddress,
94
+            serverPort,
95
+            contextPath,
96
+            env.getActiveProfiles());
97
+    }
98
+}

+ 98
- 0
src/main/java/io/github/jhipster/application/aop/logging/LoggingAspect.java 查看文件

@@ -0,0 +1,98 @@
1
+package io.github.jhipster.application.aop.logging;
2
+
3
+import io.github.jhipster.config.JHipsterConstants;
4
+
5
+import org.aspectj.lang.JoinPoint;
6
+import org.aspectj.lang.ProceedingJoinPoint;
7
+import org.aspectj.lang.annotation.AfterThrowing;
8
+import org.aspectj.lang.annotation.Around;
9
+import org.aspectj.lang.annotation.Aspect;
10
+import org.aspectj.lang.annotation.Pointcut;
11
+import org.slf4j.Logger;
12
+import org.slf4j.LoggerFactory;
13
+import org.springframework.core.env.Environment;
14
+
15
+import java.util.Arrays;
16
+
17
+/**
18
+ * Aspect for logging execution of service and repository Spring components.
19
+ *
20
+ * By default, it only runs with the "dev" profile.
21
+ */
22
+@Aspect
23
+public class LoggingAspect {
24
+
25
+    private final Logger log = LoggerFactory.getLogger(this.getClass());
26
+
27
+    private final Environment env;
28
+
29
+    public LoggingAspect(Environment env) {
30
+        this.env = env;
31
+    }
32
+
33
+    /**
34
+     * Pointcut that matches all repositories, services and Web REST endpoints.
35
+     */
36
+    @Pointcut("within(@org.springframework.stereotype.Repository *)" +
37
+        " || within(@org.springframework.stereotype.Service *)" +
38
+        " || within(@org.springframework.web.bind.annotation.RestController *)")
39
+    public void springBeanPointcut() {
40
+        // Method is empty as this is just a Pointcut, the implementations are in the advices.
41
+    }
42
+
43
+    /**
44
+     * Pointcut that matches all Spring beans in the application's main packages.
45
+     */
46
+    @Pointcut("within(io.github.jhipster.application.repository..*)"+
47
+        " || within(io.github.jhipster.application.service..*)"+
48
+        " || within(io.github.jhipster.application.web.rest..*)")
49
+    public void applicationPackagePointcut() {
50
+        // Method is empty as this is just a Pointcut, the implementations are in the advices.
51
+    }
52
+
53
+    /**
54
+     * Advice that logs methods throwing exceptions.
55
+     *
56
+     * @param joinPoint join point for advice
57
+     * @param e exception
58
+     */
59
+    @AfterThrowing(pointcut = "applicationPackagePointcut() && springBeanPointcut()", throwing = "e")
60
+    public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
61
+        if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) {
62
+            log.error("Exception in {}.{}() with cause = \'{}\' and exception = \'{}\'", joinPoint.getSignature().getDeclaringTypeName(),
63
+                joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL", e.getMessage(), e);
64
+
65
+        } else {
66
+            log.error("Exception in {}.{}() with cause = {}", joinPoint.getSignature().getDeclaringTypeName(),
67
+                joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL");
68
+        }
69
+    }
70
+
71
+    /**
72
+     * Advice that logs when a method is entered and exited.
73
+     *
74
+     * @param joinPoint join point for advice
75
+     * @return result
76
+     * @throws Throwable throws IllegalArgumentException
77
+     */
78
+    @Around("applicationPackagePointcut() && springBeanPointcut()")
79
+    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
80
+        if (log.isDebugEnabled()) {
81
+            log.debug("Enter: {}.{}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(),
82
+                joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
83
+        }
84
+        try {
85
+            Object result = joinPoint.proceed();
86
+            if (log.isDebugEnabled()) {
87
+                log.debug("Exit: {}.{}() with result = {}", joinPoint.getSignature().getDeclaringTypeName(),
88
+                    joinPoint.getSignature().getName(), result);
89
+            }
90
+            return result;
91
+        } catch (IllegalArgumentException e) {
92
+            log.error("Illegal argument: {} in {}.{}()", Arrays.toString(joinPoint.getArgs()),
93
+                joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
94
+
95
+            throw e;
96
+        }
97
+    }
98
+}

+ 14
- 0
src/main/java/io/github/jhipster/application/config/ApplicationProperties.java 查看文件

@@ -0,0 +1,14 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import org.springframework.boot.context.properties.ConfigurationProperties;
4
+
5
+/**
6
+ * Properties specific to Privy Blog.
7
+ * <p>
8
+ * Properties are configured in the application.yml file.
9
+ * See {@link io.github.jhipster.config.JHipsterProperties} for a good example.
10
+ */
11
+@ConfigurationProperties(prefix = "application", ignoreUnknownFields = false)
12
+public class ApplicationProperties {
13
+
14
+}

+ 59
- 0
src/main/java/io/github/jhipster/application/config/AsyncConfiguration.java 查看文件

@@ -0,0 +1,59 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import io.github.jhipster.async.ExceptionHandlingAsyncTaskExecutor;
4
+import io.github.jhipster.config.JHipsterProperties;
5
+
6
+import org.slf4j.Logger;
7
+import org.slf4j.LoggerFactory;
8
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
9
+import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
10
+import org.springframework.context.annotation.Bean;
11
+import org.springframework.context.annotation.Configuration;
12
+import org.springframework.scheduling.annotation.*;
13
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
14
+import org.springframework.scheduling.annotation.SchedulingConfigurer;
15
+import org.springframework.scheduling.config.ScheduledTaskRegistrar;
16
+
17
+import java.util.concurrent.Executor;
18
+import java.util.concurrent.Executors;
19
+
20
+@Configuration
21
+@EnableAsync
22
+@EnableScheduling
23
+public class AsyncConfiguration implements AsyncConfigurer, SchedulingConfigurer {
24
+
25
+    private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);
26
+
27
+    private final JHipsterProperties jHipsterProperties;
28
+
29
+    public AsyncConfiguration(JHipsterProperties jHipsterProperties) {
30
+        this.jHipsterProperties = jHipsterProperties;
31
+    }
32
+
33
+    @Override
34
+    @Bean(name = "taskExecutor")
35
+    public Executor getAsyncExecutor() {
36
+        log.debug("Creating Async Task Executor");
37
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
38
+        executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize());
39
+        executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize());
40
+        executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity());
41
+        executor.setThreadNamePrefix("privy-blog-Executor-");
42
+        return new ExceptionHandlingAsyncTaskExecutor(executor);
43
+    }
44
+
45
+    @Override
46
+    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
47
+        return new SimpleAsyncUncaughtExceptionHandler();
48
+    }
49
+    
50
+    @Override
51
+    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
52
+        taskRegistrar.setScheduler(scheduledTaskExecutor());
53
+    }
54
+
55
+    @Bean
56
+    public Executor scheduledTaskExecutor() {
57
+        return Executors.newScheduledThreadPool(jHipsterProperties.getAsync().getCorePoolSize());
58
+    }
59
+}

+ 44
- 0
src/main/java/io/github/jhipster/application/config/CacheConfiguration.java 查看文件

@@ -0,0 +1,44 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import java.time.Duration;
4
+
5
+import org.ehcache.config.builders.*;
6
+import org.ehcache.jsr107.Eh107Configuration;
7
+
8
+import io.github.jhipster.config.jcache.BeanClassLoaderAwareJCacheRegionFactory;
9
+import io.github.jhipster.config.JHipsterProperties;
10
+
11
+import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
12
+import org.springframework.cache.annotation.EnableCaching;
13
+import org.springframework.context.annotation.*;
14
+
15
+@Configuration
16
+@EnableCaching
17
+public class CacheConfiguration {
18
+
19
+    private final javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration;
20
+
21
+    public CacheConfiguration(JHipsterProperties jHipsterProperties) {
22
+        BeanClassLoaderAwareJCacheRegionFactory.setBeanClassLoader(this.getClass().getClassLoader());
23
+        JHipsterProperties.Cache.Ehcache ehcache =
24
+            jHipsterProperties.getCache().getEhcache();
25
+
26
+        jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(
27
+            CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class,
28
+                ResourcePoolsBuilder.heap(ehcache.getMaxEntries()))
29
+                .withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(ehcache.getTimeToLiveSeconds())))
30
+                .build());
31
+    }
32
+
33
+    @Bean
34
+    public JCacheManagerCustomizer cacheManagerCustomizer() {
35
+        return cm -> {
36
+            cm.createCache(io.github.jhipster.application.repository.UserRepository.USERS_BY_LOGIN_CACHE, jcacheConfiguration);
37
+            cm.createCache(io.github.jhipster.application.repository.UserRepository.USERS_BY_EMAIL_CACHE, jcacheConfiguration);
38
+            cm.createCache(io.github.jhipster.application.domain.User.class.getName(), jcacheConfiguration);
39
+            cm.createCache(io.github.jhipster.application.domain.Authority.class.getName(), jcacheConfiguration);
40
+            cm.createCache(io.github.jhipster.application.domain.User.class.getName() + ".authorities", jcacheConfiguration);
41
+            // jhipster-needle-ehcache-add-entry
42
+        };
43
+    }
44
+}

+ 28
- 0
src/main/java/io/github/jhipster/application/config/CloudDatabaseConfiguration.java 查看文件

@@ -0,0 +1,28 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import io.github.jhipster.config.JHipsterConstants;
4
+
5
+import org.slf4j.Logger;
6
+import org.slf4j.LoggerFactory;
7
+import org.springframework.cloud.config.java.AbstractCloudConfig;
8
+import org.springframework.context.annotation.*;
9
+
10
+import javax.sql.DataSource;
11
+import org.springframework.boot.context.properties.ConfigurationProperties;
12
+
13
+
14
+@Configuration
15
+@Profile(JHipsterConstants.SPRING_PROFILE_CLOUD)
16
+public class CloudDatabaseConfiguration extends AbstractCloudConfig {
17
+
18
+    private final Logger log = LoggerFactory.getLogger(CloudDatabaseConfiguration.class);
19
+    
20
+    private final String CLOUD_CONFIGURATION_HIKARI_PREFIX = "spring.datasource.hikari";
21
+
22
+    @Bean
23
+    @ConfigurationProperties(CLOUD_CONFIGURATION_HIKARI_PREFIX)
24
+    public DataSource dataSource() {
25
+        log.info("Configuring JDBC datasource from a cloud provider");
26
+        return connectionFactory().dataSource();
27
+    }
28
+}

+ 17
- 0
src/main/java/io/github/jhipster/application/config/Constants.java 查看文件

@@ -0,0 +1,17 @@
1
+package io.github.jhipster.application.config;
2
+
3
+/**
4
+ * Application constants.
5
+ */
6
+public final class Constants {
7
+
8
+    // Regex for acceptable logins
9
+    public static final String LOGIN_REGEX = "^[_.@A-Za-z0-9-]*$";
10
+
11
+    public static final String SYSTEM_ACCOUNT = "system";
12
+    public static final String ANONYMOUS_USER = "anonymoususer";
13
+    public static final String DEFAULT_LANGUAGE = "en";
14
+    
15
+    private Constants() {
16
+    }
17
+}

+ 62
- 0
src/main/java/io/github/jhipster/application/config/DatabaseConfiguration.java 查看文件

@@ -0,0 +1,62 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import io.github.jhipster.config.JHipsterConstants;
4
+import io.github.jhipster.config.h2.H2ConfigurationHelper;
5
+import org.slf4j.Logger;
6
+import org.slf4j.LoggerFactory;
7
+import org.springframework.context.annotation.Bean;
8
+import org.springframework.context.annotation.Configuration;
9
+import org.springframework.context.annotation.Profile;
10
+import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
11
+
12
+import org.springframework.core.env.Environment;
13
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
14
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
15
+import org.springframework.transaction.annotation.EnableTransactionManagement;
16
+
17
+import java.sql.SQLException;
18
+import java.lang.NumberFormatException;
19
+
20
+@Configuration
21
+@EnableJpaRepositories("io.github.jhipster.application.repository")
22
+@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
23
+@EnableTransactionManagement
24
+@EnableElasticsearchRepositories("io.github.jhipster.application.repository.search")
25
+public class DatabaseConfiguration {
26
+
27
+    private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);
28
+
29
+    private final Environment env;
30
+
31
+    public DatabaseConfiguration(Environment env) {
32
+        this.env = env;
33
+    }
34
+
35
+    /**
36
+     * Open the TCP port for the H2 database, so it is available remotely.
37
+     *
38
+     * @return the H2 database TCP server
39
+     * @throws SQLException if the server failed to start
40
+     */
41
+    @Bean(initMethod = "start", destroyMethod = "stop")
42
+    @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
43
+    public Object h2TCPServer() throws SQLException {
44
+        String port = getValidPortForH2();
45
+        log.debug("H2 database is available on port {}", port);
46
+        return H2ConfigurationHelper.createServer(port);
47
+    }
48
+	
49
+    private String getValidPortForH2() throws NumberFormatException {
50
+        int port = Integer.parseInt(env.getProperty("server.port"));
51
+        if (port < 10000) {
52
+            port = 10000 + port;
53
+        } else {
54
+            if (port < 63536) {
55
+                port = port + 2000;
56
+            } else {
57
+                port = port - 2000;
58
+            }
59
+        }
60
+        return String.valueOf(port);
61
+    }
62
+}

+ 20
- 0
src/main/java/io/github/jhipster/application/config/DateTimeFormatConfiguration.java 查看文件

@@ -0,0 +1,20 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import org.springframework.context.annotation.Configuration;
4
+import org.springframework.format.FormatterRegistry;
5
+import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
6
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
7
+
8
+/**
9
+ * Configure the converters to use the ISO format for dates by default.
10
+ */
11
+@Configuration
12
+public class DateTimeFormatConfiguration implements WebMvcConfigurer {
13
+
14
+    @Override
15
+    public void addFormatters(FormatterRegistry registry) {
16
+        DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
17
+        registrar.setUseIsoFormat(true);
18
+        registrar.registerFormatters(registry);
19
+    }
20
+}

+ 51
- 0
src/main/java/io/github/jhipster/application/config/DefaultProfileUtil.java 查看文件

@@ -0,0 +1,51 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import io.github.jhipster.config.JHipsterConstants;
4
+
5
+import org.springframework.boot.SpringApplication;
6
+import org.springframework.core.env.Environment;
7
+
8
+import java.util.*;
9
+
10
+/**
11
+ * Utility class to load a Spring profile to be used as default
12
+ * when there is no <code>spring.profiles.active</code> set in the environment or as command line argument.
13
+ * If the value is not available in <code>application.yml</code> then <code>dev</code> profile will be used as default.
14
+ */
15
+public final class DefaultProfileUtil {
16
+
17
+    private static final String SPRING_PROFILE_DEFAULT = "spring.profiles.default";
18
+
19
+    private DefaultProfileUtil() {
20
+    }
21
+
22
+    /**
23
+     * Set a default to use when no profile is configured.
24
+     *
25
+     * @param app the Spring application
26
+     */
27
+    public static void addDefaultProfile(SpringApplication app) {
28
+        Map<String, Object> defProperties = new HashMap<>();
29
+        /*
30
+        * The default profile to use when no other profiles are defined
31
+        * This cannot be set in the <code>application.yml</code> file.
32
+        * See https://github.com/spring-projects/spring-boot/issues/1219
33
+        */
34
+        defProperties.put(SPRING_PROFILE_DEFAULT, JHipsterConstants.SPRING_PROFILE_DEVELOPMENT);
35
+        app.setDefaultProperties(defProperties);
36
+    }
37
+
38
+    /**
39
+     * Get the profiles that are applied else get default profiles.
40
+     *
41
+     * @param env spring environment
42
+     * @return profiles
43
+     */
44
+    public static String[] getActiveProfiles(Environment env) {
45
+        String[] profiles = env.getActiveProfiles();
46
+        if (profiles.length == 0) {
47
+            return env.getDefaultProfiles();
48
+        }
49
+        return profiles;
50
+    }
51
+}

+ 72
- 0
src/main/java/io/github/jhipster/application/config/ElasticsearchConfiguration.java 查看文件

@@ -0,0 +1,72 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import com.fasterxml.jackson.databind.DeserializationFeature;
4
+import com.fasterxml.jackson.databind.ObjectMapper;
5
+import com.fasterxml.jackson.databind.SerializationFeature;
6
+import com.github.vanroy.springdata.jest.JestElasticsearchTemplate;
7
+import com.github.vanroy.springdata.jest.mapper.DefaultJestResultsMapper;
8
+import io.searchbox.client.JestClient;
9
+import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchProperties;
10
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
11
+import org.springframework.context.annotation.Bean;
12
+import org.springframework.context.annotation.Configuration;
13
+import org.springframework.context.annotation.Primary;
14
+import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
15
+import org.springframework.data.elasticsearch.core.EntityMapper;
16
+import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
17
+import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
18
+
19
+import java.io.IOException;
20
+
21
+@Configuration
22
+@EnableConfigurationProperties(ElasticsearchProperties.class)
23
+public class ElasticsearchConfiguration {
24
+
25
+    private ObjectMapper mapper;
26
+
27
+    public ElasticsearchConfiguration(ObjectMapper mapper) {
28
+        this.mapper = mapper;
29
+    }
30
+
31
+    @Bean
32
+    public EntityMapper getEntityMapper() {
33
+        return new CustomEntityMapper(mapper);
34
+    }
35
+
36
+    @Bean
37
+    @Primary
38
+    public ElasticsearchOperations elasticsearchTemplate(final JestClient jestClient,
39
+                                                         final ElasticsearchConverter elasticsearchConverter,
40
+                                                         final SimpleElasticsearchMappingContext simpleElasticsearchMappingContext,
41
+                                                         EntityMapper mapper) {
42
+        return new JestElasticsearchTemplate(
43
+            jestClient,
44
+            elasticsearchConverter,
45
+            new DefaultJestResultsMapper(simpleElasticsearchMappingContext, mapper));
46
+    }
47
+
48
+    public class CustomEntityMapper implements EntityMapper {
49
+
50
+        private ObjectMapper objectMapper;
51
+
52
+        public CustomEntityMapper(ObjectMapper objectMapper) {
53
+            this.objectMapper = objectMapper;
54
+            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
55
+            objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
56
+            objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, true);
57
+            objectMapper.configure(SerializationFeature.INDENT_OUTPUT, false);
58
+            objectMapper.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true);
59
+        }
60
+
61
+        @Override
62
+        public String mapToString(Object object) throws IOException {
63
+            return objectMapper.writeValueAsString(object);
64
+        }
65
+
66
+        @Override
67
+        public <T> T mapToObject(String source, Class<T> clazz) throws IOException {
68
+            return objectMapper.readValue(source, clazz);
69
+        }
70
+    }
71
+
72
+}

+ 63
- 0
src/main/java/io/github/jhipster/application/config/JacksonConfiguration.java 查看文件

@@ -0,0 +1,63 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
4
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
5
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
6
+import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
7
+
8
+import org.springframework.context.annotation.Bean;
9
+import org.springframework.context.annotation.Configuration;
10
+import org.zalando.problem.ProblemModule;
11
+import org.zalando.problem.violations.ConstraintViolationProblemModule;
12
+
13
+@Configuration
14
+public class JacksonConfiguration {
15
+
16
+    /**
17
+     * Support for Java date and time API.
18
+     * @return the corresponding Jackson module.
19
+     */
20
+    @Bean
21
+    public JavaTimeModule javaTimeModule() {
22
+        return new JavaTimeModule();
23
+    }
24
+
25
+    @Bean
26
+    public Jdk8Module jdk8TimeModule() {
27
+        return new Jdk8Module();
28
+    }
29
+
30
+
31
+    /*
32
+     * Support for Hibernate types in Jackson.
33
+     */
34
+    @Bean
35
+    public Hibernate5Module hibernate5Module() {
36
+        return new Hibernate5Module();
37
+    }
38
+
39
+    /*
40
+     * Jackson Afterburner module to speed up serialization/deserialization.
41
+     */
42
+    @Bean
43
+    public AfterburnerModule afterburnerModule() {
44
+        return new AfterburnerModule();
45
+    }
46
+
47
+    /*
48
+     * Module for serialization/deserialization of RFC7807 Problem.
49
+     */
50
+    @Bean
51
+    ProblemModule problemModule() {
52
+        return new ProblemModule();
53
+    }
54
+
55
+    /*
56
+     * Module for serialization/deserialization of ConstraintViolationProblem.
57
+     */
58
+    @Bean
59
+    ConstraintViolationProblemModule constraintViolationProblemModule() {
60
+        return new ConstraintViolationProblemModule();
61
+    }
62
+
63
+}

+ 53
- 0
src/main/java/io/github/jhipster/application/config/LiquibaseConfiguration.java 查看文件

@@ -0,0 +1,53 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import javax.sql.DataSource;
4
+
5
+import org.slf4j.Logger;
6
+import org.slf4j.LoggerFactory;
7
+import org.springframework.beans.factory.annotation.Qualifier;
8
+import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
9
+import org.springframework.cache.CacheManager;
10
+import org.springframework.context.annotation.Bean;
11
+import org.springframework.context.annotation.Configuration;
12
+import org.springframework.core.env.Environment;
13
+import org.springframework.core.task.TaskExecutor;
14
+
15
+import io.github.jhipster.config.JHipsterConstants;
16
+import io.github.jhipster.config.liquibase.AsyncSpringLiquibase;
17
+import liquibase.integration.spring.SpringLiquibase;
18
+
19
+@Configuration
20
+public class LiquibaseConfiguration {
21
+
22
+    private final Logger log = LoggerFactory.getLogger(LiquibaseConfiguration.class);
23
+
24
+    private final Environment env;
25
+
26
+    private final CacheManager cacheManager;
27
+
28
+    public LiquibaseConfiguration(Environment env, CacheManager cacheManager) {
29
+        this.env = env;
30
+        this.cacheManager = cacheManager;
31
+    }
32
+
33
+    @Bean
34
+    public SpringLiquibase liquibase(@Qualifier("taskExecutor") TaskExecutor taskExecutor,
35
+            DataSource dataSource, LiquibaseProperties liquibaseProperties) {
36
+
37
+        // Use liquibase.integration.spring.SpringLiquibase if you don't want Liquibase to start asynchronously
38
+        SpringLiquibase liquibase = new AsyncSpringLiquibase(taskExecutor, env);
39
+        liquibase.setDataSource(dataSource);
40
+        liquibase.setChangeLog("classpath:config/liquibase/master.xml");
41
+        liquibase.setContexts(liquibaseProperties.getContexts());
42
+        liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema());
43
+        liquibase.setDropFirst(liquibaseProperties.isDropFirst());
44
+        liquibase.setChangeLogParameters(liquibaseProperties.getParameters());
45
+        if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE)) {
46
+            liquibase.setShouldRun(false);
47
+        } else {
48
+            liquibase.setShouldRun(liquibaseProperties.isEnabled());
49
+            log.debug("Configuring Liquibase");
50
+        }
51
+        return liquibase;
52
+    }
53
+}

+ 27
- 0
src/main/java/io/github/jhipster/application/config/LocaleConfiguration.java 查看文件

@@ -0,0 +1,27 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import io.github.jhipster.config.locale.AngularCookieLocaleResolver;
4
+
5
+import org.springframework.context.annotation.Bean;
6
+import org.springframework.context.annotation.Configuration;
7
+import org.springframework.web.servlet.LocaleResolver;
8
+import org.springframework.web.servlet.config.annotation.*;
9
+import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
10
+
11
+@Configuration
12
+public class LocaleConfiguration implements WebMvcConfigurer {
13
+
14
+    @Bean(name = "localeResolver")
15
+    public LocaleResolver localeResolver() {
16
+        AngularCookieLocaleResolver cookieLocaleResolver = new AngularCookieLocaleResolver();
17
+        cookieLocaleResolver.setCookieName("NG_TRANSLATE_LANG_KEY");
18
+        return cookieLocaleResolver;
19
+    }
20
+
21
+    @Override
22
+    public void addInterceptors(InterceptorRegistry registry) {
23
+        LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
24
+        localeChangeInterceptor.setParamName("language");
25
+        registry.addInterceptor(localeChangeInterceptor);
26
+    }
27
+}

+ 19
- 0
src/main/java/io/github/jhipster/application/config/LoggingAspectConfiguration.java 查看文件

@@ -0,0 +1,19 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import io.github.jhipster.application.aop.logging.LoggingAspect;
4
+
5
+import io.github.jhipster.config.JHipsterConstants;
6
+
7
+import org.springframework.context.annotation.*;
8
+import org.springframework.core.env.Environment;
9
+
10
+@Configuration
11
+@EnableAspectJAutoProxy
12
+public class LoggingAspectConfiguration {
13
+
14
+    @Bean
15
+    @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
16
+    public LoggingAspect loggingAspect(Environment env) {
17
+        return new LoggingAspect(env);
18
+    }
19
+}

+ 156
- 0
src/main/java/io/github/jhipster/application/config/LoggingConfiguration.java 查看文件

@@ -0,0 +1,156 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import java.net.InetSocketAddress;
4
+import java.util.Iterator;
5
+
6
+import io.github.jhipster.config.JHipsterProperties;
7
+
8
+import ch.qos.logback.classic.AsyncAppender;
9
+import ch.qos.logback.classic.Level;
10
+import ch.qos.logback.classic.LoggerContext;
11
+import ch.qos.logback.classic.boolex.OnMarkerEvaluator;
12
+import ch.qos.logback.classic.spi.ILoggingEvent;
13
+import ch.qos.logback.classic.spi.LoggerContextListener;
14
+import ch.qos.logback.core.Appender;
15
+import ch.qos.logback.core.filter.EvaluatorFilter;
16
+import ch.qos.logback.core.spi.ContextAwareBase;
17
+import ch.qos.logback.core.spi.FilterReply;
18
+import net.logstash.logback.appender.LogstashTcpSocketAppender;
19
+import net.logstash.logback.encoder.LogstashEncoder;
20
+import net.logstash.logback.stacktrace.ShortenedThrowableConverter;
21
+import org.slf4j.Logger;
22
+import org.slf4j.LoggerFactory;
23
+import org.springframework.beans.factory.annotation.Value;
24
+import org.springframework.context.annotation.Configuration;
25
+
26
+@Configuration
27
+public class LoggingConfiguration {
28
+
29
+    private static final String LOGSTASH_APPENDER_NAME = "LOGSTASH";
30
+
31
+    private static final String ASYNC_LOGSTASH_APPENDER_NAME = "ASYNC_LOGSTASH";
32
+
33
+    private final Logger log = LoggerFactory.getLogger(LoggingConfiguration.class);
34
+
35
+    private LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
36
+
37
+    private final String appName;
38
+
39
+    private final String serverPort;
40
+
41
+    private final JHipsterProperties jHipsterProperties;
42
+
43
+    public LoggingConfiguration(@Value("${spring.application.name}") String appName, @Value("${server.port}") String serverPort,
44
+         JHipsterProperties jHipsterProperties) {
45
+        this.appName = appName;
46
+        this.serverPort = serverPort;
47
+        this.jHipsterProperties = jHipsterProperties;
48
+        if (jHipsterProperties.getLogging().getLogstash().isEnabled()) {
49
+            addLogstashAppender(context);
50
+            addContextListener(context);
51
+        }
52
+        if (jHipsterProperties.getMetrics().getLogs().isEnabled()) {
53
+            setMetricsMarkerLogbackFilter(context);
54
+        }
55
+    }
56
+
57
+    private void addContextListener(LoggerContext context) {
58
+        LogbackLoggerContextListener loggerContextListener = new LogbackLoggerContextListener();
59
+        loggerContextListener.setContext(context);
60
+        context.addListener(loggerContextListener);
61
+    }
62
+
63
+    private void addLogstashAppender(LoggerContext context) {
64
+        log.info("Initializing Logstash logging");
65
+
66
+        LogstashTcpSocketAppender logstashAppender = new LogstashTcpSocketAppender();
67
+        logstashAppender.setName(LOGSTASH_APPENDER_NAME);
68
+        logstashAppender.setContext(context);
69
+        String customFields = "{\"app_name\":\"" + appName + "\",\"app_port\":\"" + serverPort + "\"}";
70
+
71
+        // More documentation is available at: https://github.com/logstash/logstash-logback-encoder
72
+        LogstashEncoder logstashEncoder = new LogstashEncoder();
73
+        // Set the Logstash appender config from JHipster properties
74
+        logstashEncoder.setCustomFields(customFields);
75
+        // Set the Logstash appender config from JHipster properties
76
+        logstashAppender.addDestinations(new InetSocketAddress(jHipsterProperties.getLogging().getLogstash().getHost(), jHipsterProperties.getLogging().getLogstash().getPort()));
77
+
78
+        ShortenedThrowableConverter throwableConverter = new ShortenedThrowableConverter();
79
+        throwableConverter.setRootCauseFirst(true);
80
+        logstashEncoder.setThrowableConverter(throwableConverter);
81
+        logstashEncoder.setCustomFields(customFields);
82
+
83
+        logstashAppender.setEncoder(logstashEncoder);
84
+        logstashAppender.start();
85
+
86
+        // Wrap the appender in an Async appender for performance
87
+        AsyncAppender asyncLogstashAppender = new AsyncAppender();
88
+        asyncLogstashAppender.setContext(context);
89
+        asyncLogstashAppender.setName(ASYNC_LOGSTASH_APPENDER_NAME);
90
+        asyncLogstashAppender.setQueueSize(jHipsterProperties.getLogging().getLogstash().getQueueSize());
91
+        asyncLogstashAppender.addAppender(logstashAppender);
92
+        asyncLogstashAppender.start();
93
+
94
+        context.getLogger("ROOT").addAppender(asyncLogstashAppender);
95
+    }
96
+
97
+    // Configure a log filter to remove "metrics" logs from all appenders except the "LOGSTASH" appender
98
+    private void setMetricsMarkerLogbackFilter(LoggerContext context) {
99
+        log.info("Filtering metrics logs from all appenders except the {} appender", LOGSTASH_APPENDER_NAME);
100
+        OnMarkerEvaluator onMarkerMetricsEvaluator = new OnMarkerEvaluator();
101
+        onMarkerMetricsEvaluator.setContext(context);
102
+        onMarkerMetricsEvaluator.addMarker("metrics");
103
+        onMarkerMetricsEvaluator.start();
104
+        EvaluatorFilter<ILoggingEvent> metricsFilter = new EvaluatorFilter<>();
105
+        metricsFilter.setContext(context);
106
+        metricsFilter.setEvaluator(onMarkerMetricsEvaluator);
107
+        metricsFilter.setOnMatch(FilterReply.DENY);
108
+        metricsFilter.start();
109
+
110
+        for (ch.qos.logback.classic.Logger logger : context.getLoggerList()) {
111
+            for (Iterator<Appender<ILoggingEvent>> it = logger.iteratorForAppenders(); it.hasNext();) {
112
+                Appender<ILoggingEvent> appender = it.next();
113
+                if (!appender.getName().equals(ASYNC_LOGSTASH_APPENDER_NAME)) {
114
+                    log.debug("Filter metrics logs from the {} appender", appender.getName());
115
+                    appender.setContext(context);
116
+                    appender.addFilter(metricsFilter);
117
+                    appender.start();
118
+                }
119
+            }
120
+        }
121
+    }
122
+
123
+    /**
124
+     * Logback configuration is achieved by configuration file and API.
125
+     * When configuration file change is detected, the configuration is reset.
126
+     * This listener ensures that the programmatic configuration is also re-applied after reset.
127
+     */
128
+    class LogbackLoggerContextListener extends ContextAwareBase implements LoggerContextListener {
129
+
130
+        @Override
131
+        public boolean isResetResistant() {
132
+            return true;
133
+        }
134
+
135
+        @Override
136
+        public void onStart(LoggerContext context) {
137
+            addLogstashAppender(context);
138
+        }
139
+
140
+        @Override
141
+        public void onReset(LoggerContext context) {
142
+            addLogstashAppender(context);
143
+        }
144
+
145
+        @Override
146
+        public void onStop(LoggerContext context) {
147
+            // Nothing to do.
148
+        }
149
+
150
+        @Override
151
+        public void onLevelChange(ch.qos.logback.classic.Logger logger, Level level) {
152
+            // Nothing to do.
153
+        }
154
+    }
155
+
156
+}

+ 41
- 0
src/main/java/io/github/jhipster/application/config/MessagingConfiguration.java 查看文件

@@ -0,0 +1,41 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import java.time.LocalDateTime;
4
+import java.time.format.DateTimeFormatter;
5
+
6
+import org.springframework.cloud.stream.annotation.EnableBinding;
7
+import org.springframework.cloud.stream.messaging.Source;
8
+import org.springframework.beans.factory.annotation.Value;
9
+import org.springframework.context.annotation.Bean;
10
+import org.springframework.integration.annotation.InboundChannelAdapter;
11
+import org.springframework.integration.annotation.Poller;
12
+import org.springframework.integration.core.MessageSource;
13
+import org.springframework.messaging.support.GenericMessage;
14
+
15
+/**
16
+ * Configures Spring Cloud Stream support.
17
+ *
18
+ * This works out-of-the-box if you use the Docker Compose configuration at "src/main/docker/kafka.yml".
19
+ *
20
+ * See http://docs.spring.io/spring-cloud-stream/docs/current/reference/htmlsingle/
21
+ * for the official Spring Cloud Stream documentation.
22
+ */
23
+@EnableBinding(value = { Source.class })
24
+public class MessagingConfiguration {
25
+
26
+    @Value("${spring.application.name:JhipsterService}")
27
+    private String applicationName;
28
+
29
+    /**
30
+     * This sends a test message at regular intervals set as fixedRate (in ms)
31
+     *
32
+     * In order to see the test messages, you can use the Kafka command-line client:
33
+     * "./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic topic-jhipster --from-beginning".
34
+     */
35
+    @Bean
36
+    @InboundChannelAdapter(value = Source.OUTPUT, poller = @Poller(fixedRate = "60000"))
37
+    public MessageSource<String> timerMessageSource() {
38
+        return () -> new GenericMessage<>("Test message from " + applicationName
39
+            + " sent at " + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
40
+    }
41
+}

+ 126
- 0
src/main/java/io/github/jhipster/application/config/MetricsConfiguration.java 查看文件

@@ -0,0 +1,126 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import io.github.jhipster.config.JHipsterProperties;
4
+
5
+import com.codahale.metrics.JmxReporter;
6
+import com.codahale.metrics.JvmAttributeGaugeSet;
7
+import com.codahale.metrics.MetricRegistry;
8
+import com.codahale.metrics.Slf4jReporter;
9
+import com.codahale.metrics.health.HealthCheckRegistry;
10
+import com.codahale.metrics.jcache.JCacheGaugeSet;
11
+import com.codahale.metrics.jvm.*;
12
+import com.ryantenney.metrics.spring.config.annotation.EnableMetrics;
13
+import com.ryantenney.metrics.spring.config.annotation.MetricsConfigurerAdapter;
14
+import com.zaxxer.hikari.HikariDataSource;
15
+import io.prometheus.client.CollectorRegistry;
16
+import io.prometheus.client.dropwizard.DropwizardExports;
17
+import io.prometheus.client.exporter.MetricsServlet;
18
+import org.slf4j.Logger;
19
+import org.slf4j.LoggerFactory;
20
+import org.slf4j.Marker;
21
+import org.slf4j.MarkerFactory;
22
+import org.springframework.beans.factory.annotation.Autowired;
23
+import org.springframework.boot.web.servlet.ServletContextInitializer;
24
+import org.springframework.cache.CacheManager;
25
+import org.springframework.context.annotation.*;
26
+
27
+import javax.annotation.PostConstruct;
28
+import javax.servlet.ServletContext;
29
+import java.lang.management.ManagementFactory;
30
+import java.util.concurrent.TimeUnit;
31
+
32
+@Configuration
33
+@EnableMetrics(proxyTargetClass = true)
34
+public class MetricsConfiguration extends MetricsConfigurerAdapter implements ServletContextInitializer {
35
+
36
+    private static final String PROP_METRIC_REG_JVM_MEMORY = "jvm.memory";
37
+    private static final String PROP_METRIC_REG_JVM_GARBAGE = "jvm.garbage";
38
+    private static final String PROP_METRIC_REG_JVM_THREADS = "jvm.threads";
39
+    private static final String PROP_METRIC_REG_JVM_FILES = "jvm.files";
40
+    private static final String PROP_METRIC_REG_JVM_BUFFERS = "jvm.buffers";
41
+    private static final String PROP_METRIC_REG_JVM_ATTRIBUTE_SET = "jvm.attributes";
42
+
43
+    private static final String PROP_METRIC_REG_JCACHE_STATISTICS = "jcache.statistics";
44
+
45
+    private final Logger log = LoggerFactory.getLogger(MetricsConfiguration.class);
46
+
47
+    private MetricRegistry metricRegistry = new MetricRegistry();
48
+
49
+    private HealthCheckRegistry healthCheckRegistry = new HealthCheckRegistry();
50
+
51
+    private final JHipsterProperties jHipsterProperties;
52
+
53
+    private HikariDataSource hikariDataSource;
54
+
55
+    // The cacheManager is injected here to force its initialization, so the JCacheGaugeSet
56
+    // will be correctly created below.
57
+    public MetricsConfiguration(JHipsterProperties jHipsterProperties, CacheManager cacheManager) {
58
+        this.jHipsterProperties = jHipsterProperties;
59
+    }
60
+
61
+    @Autowired(required = false)
62
+    public void setHikariDataSource(HikariDataSource hikariDataSource) {
63
+        this.hikariDataSource = hikariDataSource;
64
+    }
65
+
66
+    @Override
67
+    @Bean
68
+    public MetricRegistry getMetricRegistry() {
69
+        return metricRegistry;
70
+    }
71
+
72
+    @Override
73
+    @Bean
74
+    public HealthCheckRegistry getHealthCheckRegistry() {
75
+        return healthCheckRegistry;
76
+    }
77
+
78
+    @PostConstruct
79
+    public void init() {
80
+        log.debug("Registering JVM gauges");
81
+        metricRegistry.register(PROP_METRIC_REG_JVM_MEMORY, new MemoryUsageGaugeSet());
82
+        metricRegistry.register(PROP_METRIC_REG_JVM_GARBAGE, new GarbageCollectorMetricSet());
83
+        metricRegistry.register(PROP_METRIC_REG_JVM_THREADS, new ThreadStatesGaugeSet());
84
+        metricRegistry.register(PROP_METRIC_REG_JVM_FILES, new FileDescriptorRatioGauge());
85
+        metricRegistry.register(PROP_METRIC_REG_JVM_BUFFERS, new BufferPoolMetricSet(ManagementFactory.getPlatformMBeanServer()));
86
+        metricRegistry.register(PROP_METRIC_REG_JVM_ATTRIBUTE_SET, new JvmAttributeGaugeSet());
87
+        metricRegistry.register(PROP_METRIC_REG_JCACHE_STATISTICS, new JCacheGaugeSet());
88
+        if (hikariDataSource != null) {
89
+            log.debug("Monitoring the datasource");
90
+            // remove the factory created by HikariDataSourceMetricsPostProcessor until JHipster migrate to Micrometer
91
+            hikariDataSource.setMetricsTrackerFactory(null);
92
+            hikariDataSource.setMetricRegistry(metricRegistry);
93
+        }
94
+        if (jHipsterProperties.getMetrics().getJmx().isEnabled()) {
95
+            log.debug("Initializing Metrics JMX reporting");
96
+            JmxReporter jmxReporter = JmxReporter.forRegistry(metricRegistry).build();
97
+            jmxReporter.start();
98
+        }
99
+        if (jHipsterProperties.getMetrics().getLogs().isEnabled()) {
100
+            log.info("Initializing Metrics Log reporting");
101
+            Marker metricsMarker = MarkerFactory.getMarker("metrics");
102
+            final Slf4jReporter reporter = Slf4jReporter.forRegistry(metricRegistry)
103
+                .outputTo(LoggerFactory.getLogger("metrics"))
104
+                .markWith(metricsMarker)
105
+                .convertRatesTo(TimeUnit.SECONDS)
106
+                .convertDurationsTo(TimeUnit.MILLISECONDS)
107
+                .build();
108
+            reporter.start(jHipsterProperties.getMetrics().getLogs().getReportFrequency(), TimeUnit.SECONDS);
109
+        }
110
+    }
111
+
112
+    @Override
113
+    public void onStartup(ServletContext servletContext) {
114
+
115
+        if (jHipsterProperties.getMetrics().getPrometheus().isEnabled()) {
116
+            String endpoint = jHipsterProperties.getMetrics().getPrometheus().getEndpoint();
117
+
118
+            log.debug("Initializing prometheus metrics exporting via {}", endpoint);
119
+
120
+            CollectorRegistry.defaultRegistry.register(new DropwizardExports(metricRegistry));
121
+            servletContext
122
+                .addServlet("prometheusMetrics", new MetricsServlet(CollectorRegistry.defaultRegistry))
123
+                .addMapping(endpoint);
124
+        }
125
+    }
126
+}

+ 123
- 0
src/main/java/io/github/jhipster/application/config/SecurityConfiguration.java 查看文件

@@ -0,0 +1,123 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import io.github.jhipster.application.security.*;
4
+import io.github.jhipster.application.security.jwt.*;
5
+
6
+import org.springframework.beans.factory.BeanInitializationException;
7
+import org.springframework.context.annotation.Bean;
8
+import org.springframework.context.annotation.Configuration;
9
+import org.springframework.context.annotation.Import;
10
+import org.springframework.http.HttpMethod;
11
+import org.springframework.security.authentication.AuthenticationManager;
12
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
13
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
14
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
15
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
16
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
17
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
18
+import org.springframework.security.config.http.SessionCreationPolicy;
19
+import org.springframework.security.core.userdetails.UserDetailsService;
20
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
21
+import org.springframework.security.crypto.password.PasswordEncoder;
22
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
23
+import org.springframework.web.filter.CorsFilter;
24
+import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport;
25
+
26
+import javax.annotation.PostConstruct;
27
+
28
+@Configuration
29
+@EnableWebSecurity
30
+@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
31
+@Import(SecurityProblemSupport.class)
32
+public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
33
+
34
+    private final AuthenticationManagerBuilder authenticationManagerBuilder;
35
+
36
+    private final UserDetailsService userDetailsService;
37
+
38
+    private final TokenProvider tokenProvider;
39
+
40
+    private final CorsFilter corsFilter;
41
+
42
+    private final SecurityProblemSupport problemSupport;
43
+
44
+    public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, UserDetailsService userDetailsService, TokenProvider tokenProvider, CorsFilter corsFilter, SecurityProblemSupport problemSupport) {
45
+        this.authenticationManagerBuilder = authenticationManagerBuilder;
46
+        this.userDetailsService = userDetailsService;
47
+        this.tokenProvider = tokenProvider;
48
+        this.corsFilter = corsFilter;
49
+        this.problemSupport = problemSupport;
50
+    }
51
+
52
+    @PostConstruct
53
+    public void init() {
54
+        try {
55
+            authenticationManagerBuilder
56
+                .userDetailsService(userDetailsService)
57
+                .passwordEncoder(passwordEncoder());
58
+        } catch (Exception e) {
59
+            throw new BeanInitializationException("Security configuration failed", e);
60
+        }
61
+    }
62
+
63
+    @Override
64
+    @Bean
65
+    public AuthenticationManager authenticationManagerBean() throws Exception {
66
+        return super.authenticationManagerBean();
67
+    }
68
+
69
+    @Bean
70
+    public PasswordEncoder passwordEncoder() {
71
+        return new BCryptPasswordEncoder();
72
+    }
73
+
74
+    @Override
75
+    public void configure(WebSecurity web) throws Exception {
76
+        web.ignoring()
77
+            .antMatchers(HttpMethod.OPTIONS, "/**")
78
+            .antMatchers("/app/**/*.{js,html}")
79
+            .antMatchers("/i18n/**")
80
+            .antMatchers("/content/**")
81
+            .antMatchers("/h2-console/**")
82
+            .antMatchers("/swagger-ui/index.html")
83
+            .antMatchers("/test/**");
84
+    }
85
+
86
+    @Override
87
+    public void configure(HttpSecurity http) throws Exception {
88
+        http
89
+            .csrf()
90
+            .disable()
91
+            .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
92
+            .exceptionHandling()
93
+            .authenticationEntryPoint(problemSupport)
94
+            .accessDeniedHandler(problemSupport)
95
+        .and()
96
+            .headers()
97
+            .frameOptions()
98
+            .disable()
99
+        .and()
100
+            .sessionManagement()
101
+            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
102
+        .and()
103
+            .authorizeRequests()
104
+            .antMatchers("/api/register").permitAll()
105
+            .antMatchers("/api/activate").permitAll()
106
+            .antMatchers("/api/authenticate").permitAll()
107
+            .antMatchers("/api/account/reset-password/init").permitAll()
108
+            .antMatchers("/api/account/reset-password/finish").permitAll()
109
+            .antMatchers("/api/**").authenticated()
110
+            .antMatchers("/websocket/tracker").hasAuthority(AuthoritiesConstants.ADMIN)
111
+            .antMatchers("/websocket/**").permitAll()
112
+            .antMatchers("/management/health").permitAll()
113
+            .antMatchers("/management/info").permitAll()
114
+            .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
115
+        .and()
116
+            .apply(securityConfigurerAdapter());
117
+
118
+    }
119
+
120
+    private JWTConfigurer securityConfigurerAdapter() {
121
+        return new JWTConfigurer(tokenProvider);
122
+    }
123
+}

+ 206
- 0
src/main/java/io/github/jhipster/application/config/WebConfigurer.java 查看文件

@@ -0,0 +1,206 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import com.codahale.metrics.MetricRegistry;
4
+import com.codahale.metrics.servlet.InstrumentedFilter;
5
+import com.codahale.metrics.servlets.MetricsServlet;
6
+import io.github.jhipster.config.JHipsterConstants;
7
+import io.github.jhipster.config.JHipsterProperties;
8
+import io.github.jhipster.config.h2.H2ConfigurationHelper;
9
+import io.github.jhipster.web.filter.CachingHttpHeadersFilter;
10
+import io.undertow.UndertowOptions;
11
+import org.slf4j.Logger;
12
+import org.slf4j.LoggerFactory;
13
+import org.springframework.beans.factory.annotation.Autowired;
14
+import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
15
+import org.springframework.boot.web.server.*;
16
+import org.springframework.boot.web.servlet.ServletContextInitializer;
17
+import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
18
+import org.springframework.context.annotation.Bean;
19
+import org.springframework.context.annotation.Configuration;
20
+import org.springframework.core.env.Environment;
21
+import org.springframework.http.MediaType;
22
+import org.springframework.web.cors.CorsConfiguration;
23
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
24
+import org.springframework.web.filter.CorsFilter;
25
+
26
+import javax.servlet.*;
27
+import java.io.File;
28
+import java.io.UnsupportedEncodingException;
29
+import java.nio.charset.StandardCharsets;
30
+import java.nio.file.Paths;
31
+import java.util.*;
32
+
33
+import static java.net.URLDecoder.decode;
34
+
35
+/**
36
+ * Configuration of web application with Servlet 3.0 APIs.
37
+ */
38
+@Configuration
39
+public class WebConfigurer implements ServletContextInitializer, WebServerFactoryCustomizer<WebServerFactory> {
40
+
41
+    private final Logger log = LoggerFactory.getLogger(WebConfigurer.class);
42
+
43
+    private final Environment env;
44
+
45
+    private final JHipsterProperties jHipsterProperties;
46
+
47
+    private MetricRegistry metricRegistry;
48
+
49
+    public WebConfigurer(Environment env, JHipsterProperties jHipsterProperties) {
50
+
51
+        this.env = env;
52
+        this.jHipsterProperties = jHipsterProperties;
53
+    }
54
+
55
+    @Override
56
+    public void onStartup(ServletContext servletContext) throws ServletException {
57
+        if (env.getActiveProfiles().length != 0) {
58
+            log.info("Web application configuration, using profiles: {}", (Object[]) env.getActiveProfiles());
59
+        }
60
+        EnumSet<DispatcherType> disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC);
61
+        initMetrics(servletContext, disps);
62
+        if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) {
63
+            initCachingHttpHeadersFilter(servletContext, disps);
64
+        }
65
+        if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) {
66
+            initH2Console(servletContext);
67
+        }
68
+        log.info("Web application fully configured");
69
+    }
70
+
71
+    /**
72
+     * Customize the Servlet engine: Mime types, the document root, the cache.
73
+     */
74
+    @Override
75
+    public void customize(WebServerFactory server) {
76
+        setMimeMappings(server);
77
+        // When running in an IDE or with ./mvnw spring-boot:run, set location of the static web assets.
78
+        setLocationForStaticAssets(server);
79
+
80
+        /*
81
+         * Enable HTTP/2 for Undertow - https://twitter.com/ankinson/status/829256167700492288
82
+         * HTTP/2 requires HTTPS, so HTTP requests will fallback to HTTP/1.1.
83
+         * See the JHipsterProperties class and your application-*.yml configuration files
84
+         * for more information.
85
+         */
86
+        if (jHipsterProperties.getHttp().getVersion().equals(JHipsterProperties.Http.Version.V_2_0) &&
87
+            server instanceof UndertowServletWebServerFactory) {
88
+
89
+            ((UndertowServletWebServerFactory) server)
90
+                .addBuilderCustomizers(builder ->
91
+                    builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true));
92
+        }
93
+    }
94
+
95
+    private void setMimeMappings(WebServerFactory server) {
96
+        if (server instanceof ConfigurableServletWebServerFactory) {
97
+            MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
98
+            // IE issue, see https://github.com/jhipster/generator-jhipster/pull/711
99
+            mappings.add("html", MediaType.TEXT_HTML_VALUE + ";charset=" + StandardCharsets.UTF_8.name().toLowerCase());
100
+            // CloudFoundry issue, see https://github.com/cloudfoundry/gorouter/issues/64
101
+            mappings.add("json", MediaType.TEXT_HTML_VALUE + ";charset=" + StandardCharsets.UTF_8.name().toLowerCase());
102
+            ConfigurableServletWebServerFactory servletWebServer = (ConfigurableServletWebServerFactory) server;
103
+            servletWebServer.setMimeMappings(mappings);
104
+        }
105
+    }
106
+
107
+    private void setLocationForStaticAssets(WebServerFactory server) {
108
+        if (server instanceof ConfigurableServletWebServerFactory) {
109
+            ConfigurableServletWebServerFactory servletWebServer = (ConfigurableServletWebServerFactory) server;
110
+            File root;
111
+            String prefixPath = resolvePathPrefix();
112
+            root = new File(prefixPath + "target/www/");
113
+            if (root.exists() && root.isDirectory()) {
114
+                servletWebServer.setDocumentRoot(root);
115
+            }
116
+        }
117
+    }
118
+
119
+    /**
120
+     * Resolve path prefix to static resources.
121
+     */
122
+    private String resolvePathPrefix() {
123
+        String fullExecutablePath;
124
+        try {
125
+            fullExecutablePath = decode(this.getClass().getResource("").getPath(), StandardCharsets.UTF_8.name());
126
+        } catch (UnsupportedEncodingException e) {
127
+            /* try without decoding if this ever happens */
128
+            fullExecutablePath = this.getClass().getResource("").getPath();
129
+        }
130
+        String rootPath = Paths.get(".").toUri().normalize().getPath();
131
+        String extractedPath = fullExecutablePath.replace(rootPath, "");
132
+        int extractionEndIndex = extractedPath.indexOf("target/");
133
+        if (extractionEndIndex <= 0) {
134
+            return "";
135
+        }
136
+        return extractedPath.substring(0, extractionEndIndex);
137
+    }
138
+
139
+    /**
140
+     * Initializes the caching HTTP Headers Filter.
141
+     */
142
+    private void initCachingHttpHeadersFilter(ServletContext servletContext,
143
+                                              EnumSet<DispatcherType> disps) {
144
+        log.debug("Registering Caching HTTP Headers Filter");
145
+        FilterRegistration.Dynamic cachingHttpHeadersFilter =
146
+            servletContext.addFilter("cachingHttpHeadersFilter",
147
+                new CachingHttpHeadersFilter(jHipsterProperties));
148
+
149
+        cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/i18n/*");
150
+        cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/content/*");
151
+        cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/app/*");
152
+        cachingHttpHeadersFilter.setAsyncSupported(true);
153
+    }
154
+
155
+    /**
156
+     * Initializes Metrics.
157
+     */
158
+    private void initMetrics(ServletContext servletContext, EnumSet<DispatcherType> disps) {
159
+        log.debug("Initializing Metrics registries");
160
+        servletContext.setAttribute(InstrumentedFilter.REGISTRY_ATTRIBUTE,
161
+            metricRegistry);
162
+        servletContext.setAttribute(MetricsServlet.METRICS_REGISTRY,
163
+            metricRegistry);
164
+
165
+        log.debug("Registering Metrics Filter");
166
+        FilterRegistration.Dynamic metricsFilter = servletContext.addFilter("webappMetricsFilter",
167
+            new InstrumentedFilter());
168
+
169
+        metricsFilter.addMappingForUrlPatterns(disps, true, "/*");
170
+        metricsFilter.setAsyncSupported(true);
171
+
172
+        log.debug("Registering Metrics Servlet");
173
+        ServletRegistration.Dynamic metricsAdminServlet =
174
+            servletContext.addServlet("metricsServlet", new MetricsServlet());
175
+
176
+        metricsAdminServlet.addMapping("/management/metrics/*");
177
+        metricsAdminServlet.setAsyncSupported(true);
178
+        metricsAdminServlet.setLoadOnStartup(2);
179
+    }
180
+
181
+    @Bean
182
+    public CorsFilter corsFilter() {
183
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
184
+        CorsConfiguration config = jHipsterProperties.getCors();
185
+        if (config.getAllowedOrigins() != null && !config.getAllowedOrigins().isEmpty()) {
186
+            log.debug("Registering CORS filter");
187
+            source.registerCorsConfiguration("/api/**", config);
188
+            source.registerCorsConfiguration("/management/**", config);
189
+            source.registerCorsConfiguration("/v2/api-docs", config);
190
+        }
191
+        return new CorsFilter(source);
192
+    }
193
+
194
+    /**
195
+     * Initializes H2 console.
196
+     */
197
+    private void initH2Console(ServletContext servletContext) {
198
+        log.debug("Initialize H2 console");
199
+        H2ConfigurationHelper.initH2Console(servletContext);
200
+    }
201
+
202
+    @Autowired(required = false)
203
+    public void setMetricRegistry(MetricRegistry metricRegistry) {
204
+        this.metricRegistry = metricRegistry;
205
+    }
206
+}

+ 82
- 0
src/main/java/io/github/jhipster/application/config/WebsocketConfiguration.java 查看文件

@@ -0,0 +1,82 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import io.github.jhipster.application.security.AuthoritiesConstants;
4
+
5
+import java.security.Principal;
6
+import java.util.*;
7
+
8
+import org.springframework.context.annotation.Bean;
9
+import org.springframework.context.annotation.Configuration;
10
+import org.springframework.http.server.*;
11
+import org.springframework.messaging.simp.config.MessageBrokerRegistry;
12
+import org.springframework.security.authentication.AnonymousAuthenticationToken;
13
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
14
+import org.springframework.web.socket.WebSocketHandler;
15
+import org.springframework.web.socket.config.annotation.*;
16
+import org.springframework.web.socket.server.HandshakeInterceptor;
17
+import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
18
+
19
+import io.github.jhipster.config.JHipsterProperties;
20
+
21
+@Configuration
22
+@EnableWebSocketMessageBroker
23
+public class WebsocketConfiguration implements WebSocketMessageBrokerConfigurer {
24
+
25
+    public static final String IP_ADDRESS = "IP_ADDRESS";
26
+
27
+    private final JHipsterProperties jHipsterProperties;
28
+
29
+    public WebsocketConfiguration(JHipsterProperties jHipsterProperties) {
30
+        this.jHipsterProperties = jHipsterProperties;
31
+    }
32
+
33
+    @Override
34
+    public void configureMessageBroker(MessageBrokerRegistry config) {
35
+        config.enableSimpleBroker("/topic");
36
+    }
37
+
38
+    @Override
39
+    public void registerStompEndpoints(StompEndpointRegistry registry) {
40
+        String[] allowedOrigins = Optional.ofNullable(jHipsterProperties.getCors().getAllowedOrigins()).map(origins -> origins.toArray(new String[0])).orElse(new String[0]);
41
+        registry.addEndpoint("/websocket/tracker")
42
+            .setHandshakeHandler(defaultHandshakeHandler())
43
+            .setAllowedOrigins(allowedOrigins)
44
+            .withSockJS()
45
+            .setInterceptors(httpSessionHandshakeInterceptor());
46
+    }
47
+
48
+    @Bean
49
+    public HandshakeInterceptor httpSessionHandshakeInterceptor() {
50
+        return new HandshakeInterceptor() {
51
+
52
+            @Override
53
+            public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
54
+                if (request instanceof ServletServerHttpRequest) {
55
+                    ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
56
+                    attributes.put(IP_ADDRESS, servletRequest.getRemoteAddress());
57
+                }
58
+                return true;
59
+            }
60
+
61
+            @Override
62
+            public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
63
+
64
+            }
65
+        };
66
+    }
67
+
68
+    private DefaultHandshakeHandler defaultHandshakeHandler() {
69
+        return new DefaultHandshakeHandler() {
70
+            @Override
71
+            protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
72
+                Principal principal = request.getPrincipal();
73
+                if (principal == null) {
74
+                    Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
75
+                    authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS));
76
+                    principal = new AnonymousAuthenticationToken("WebsocketConfiguration", "anonymous", authorities);
77
+                }
78
+                return principal;
79
+            }
80
+        };
81
+    }
82
+}

+ 35
- 0
src/main/java/io/github/jhipster/application/config/WebsocketSecurityConfiguration.java 查看文件

@@ -0,0 +1,35 @@
1
+package io.github.jhipster.application.config;
2
+
3
+import io.github.jhipster.application.security.AuthoritiesConstants;
4
+import org.springframework.context.annotation.Configuration;
5
+import org.springframework.messaging.simp.SimpMessageType;
6
+import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;
7
+import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer;
8
+
9
+@Configuration
10
+public class WebsocketSecurityConfiguration extends AbstractSecurityWebSocketMessageBrokerConfigurer {
11
+
12
+    @Override
13
+    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
14
+        messages
15
+            .nullDestMatcher().authenticated()
16
+            .simpDestMatchers("/topic/tracker").hasAuthority(AuthoritiesConstants.ADMIN)
17
+            // matches any destination that starts with /topic/
18
+            // (i.e. cannot send messages directly to /topic/)
19
+            // (i.e. cannot subscribe to /topic/messages/* to get messages sent to
20
+            // /topic/messages-user<id>)
21
+            .simpDestMatchers("/topic/**").authenticated()
22
+            // message types other than MESSAGE and SUBSCRIBE
23
+            .simpTypeMatchers(SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE).denyAll()
24
+            // catch all
25
+            .anyMessage().denyAll();
26
+    }
27
+
28
+    /**
29
+     * Disables CSRF for Websockets.
30
+     */
31
+    @Override
32
+    protected boolean sameOriginDisabled() {
33
+        return true;
34
+    }
35
+}

+ 86
- 0
src/main/java/io/github/jhipster/application/config/audit/AuditEventConverter.java 查看文件

@@ -0,0 +1,86 @@
1
+package io.github.jhipster.application.config.audit;
2
+
3
+import io.github.jhipster.application.domain.PersistentAuditEvent;
4
+
5
+import org.springframework.boot.actuate.audit.AuditEvent;
6
+import org.springframework.security.web.authentication.WebAuthenticationDetails;
7
+import org.springframework.stereotype.Component;
8
+
9
+import java.util.*;
10
+
11
+@Component
12
+public class AuditEventConverter {
13
+
14
+    /**
15
+     * Convert a list of PersistentAuditEvent to a list of AuditEvent
16
+     *
17
+     * @param persistentAuditEvents the list to convert
18
+     * @return the converted list.
19
+     */
20
+    public List<AuditEvent> convertToAuditEvent(Iterable<PersistentAuditEvent> persistentAuditEvents) {
21
+        if (persistentAuditEvents == null) {
22
+            return Collections.emptyList();
23
+        }
24
+        List<AuditEvent> auditEvents = new ArrayList<>();
25
+        for (PersistentAuditEvent persistentAuditEvent : persistentAuditEvents) {
26
+            auditEvents.add(convertToAuditEvent(persistentAuditEvent));
27
+        }
28
+        return auditEvents;
29
+    }
30
+
31
+    /**
32
+     * Convert a PersistentAuditEvent to an AuditEvent
33
+     *
34
+     * @param persistentAuditEvent the event to convert
35
+     * @return the converted list.
36
+     */
37
+    public AuditEvent convertToAuditEvent(PersistentAuditEvent persistentAuditEvent) {
38
+        if (persistentAuditEvent == null) {
39
+            return null;
40
+        }
41
+        return new AuditEvent(persistentAuditEvent.getAuditEventDate(), persistentAuditEvent.getPrincipal(),
42
+            persistentAuditEvent.getAuditEventType(), convertDataToObjects(persistentAuditEvent.getData()));
43
+    }
44
+
45
+    /**
46
+     * Internal conversion. This is needed to support the current SpringBoot actuator AuditEventRepository interface
47
+     *
48
+     * @param data the data to convert
49
+     * @return a map of String, Object
50
+     */
51
+    public Map<String, Object> convertDataToObjects(Map<String, String> data) {
52
+        Map<String, Object> results = new HashMap<>();
53
+
54
+        if (data != null) {
55
+            for (Map.Entry<String, String> entry : data.entrySet()) {
56
+                results.put(entry.getKey(), entry.getValue());
57
+            }
58
+        }
59
+        return results;
60
+    }
61
+
62
+    /**
63
+     * Internal conversion. This method will allow to save additional data.
64
+     * By default, it will save the object as string
65
+     *
66
+     * @param data the data to convert
67
+     * @return a map of String, String
68
+     */
69
+    public Map<String, String> convertDataToStrings(Map<String, Object> data) {
70
+        Map<String, String> results = new HashMap<>();
71
+
72
+        if (data != null) {
73
+            for (Map.Entry<String, Object> entry : data.entrySet()) {
74
+                // Extract the data that will be saved.
75
+                if (entry.getValue() instanceof WebAuthenticationDetails) {
76
+                    WebAuthenticationDetails authenticationDetails = (WebAuthenticationDetails) entry.getValue();
77
+                    results.put("remoteAddress", authenticationDetails.getRemoteAddress());
78
+                    results.put("sessionId", authenticationDetails.getSessionId());
79
+                } else {
80
+                    results.put(entry.getKey(), Objects.toString(entry.getValue()));
81
+                }
82
+            }
83
+        }
84
+        return results;
85
+    }
86
+}

+ 4
- 0
src/main/java/io/github/jhipster/application/config/audit/package-info.java 查看文件

@@ -0,0 +1,4 @@
1
+/**
2
+ * Audit specific code.
3
+ */
4
+package io.github.jhipster.application.config.audit;

+ 4
- 0
src/main/java/io/github/jhipster/application/config/package-info.java 查看文件

@@ -0,0 +1,4 @@
1
+/**
2
+ * Spring Framework configuration files.
3
+ */
4
+package io.github.jhipster.application.config;

+ 79
- 0
src/main/java/io/github/jhipster/application/domain/AbstractAuditingEntity.java 查看文件

@@ -0,0 +1,79 @@
1
+package io.github.jhipster.application.domain;
2
+
3
+import com.fasterxml.jackson.annotation.JsonIgnore;
4
+import org.hibernate.envers.Audited;
5
+import org.springframework.data.annotation.CreatedBy;
6
+import org.springframework.data.annotation.CreatedDate;
7
+import org.springframework.data.annotation.LastModifiedBy;
8
+import org.springframework.data.annotation.LastModifiedDate;
9
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
10
+
11
+import java.io.Serializable;
12
+import java.time.Instant;
13
+import javax.persistence.Column;
14
+import javax.persistence.EntityListeners;
15
+import javax.persistence.MappedSuperclass;
16
+
17
+/**
18
+ * Base abstract class for entities which will hold definitions for created, last modified by and created,
19
+ * last modified by date.
20
+ */
21
+@MappedSuperclass
22
+@Audited
23
+@EntityListeners(AuditingEntityListener.class)
24
+public abstract class AbstractAuditingEntity implements Serializable {
25
+
26
+    private static final long serialVersionUID = 1L;
27
+
28
+    @CreatedBy
29
+    @Column(name = "created_by", nullable = false, length = 50, updatable = false)
30
+    @JsonIgnore
31
+    private String createdBy;
32
+
33
+    @CreatedDate
34
+    @Column(name = "created_date", updatable = false)
35
+    @JsonIgnore
36
+    private Instant createdDate = Instant.now();
37
+
38
+    @LastModifiedBy
39
+    @Column(name = "last_modified_by", length = 50)
40
+    @JsonIgnore
41
+    private String lastModifiedBy;
42
+
43
+    @LastModifiedDate
44
+    @Column(name = "last_modified_date")
45
+    @JsonIgnore
46
+    private Instant lastModifiedDate = Instant.now();
47
+
48
+    public String getCreatedBy() {
49
+        return createdBy;
50
+    }
51
+
52
+    public void setCreatedBy(String createdBy) {
53
+        this.createdBy = createdBy;
54
+    }
55
+
56
+    public Instant getCreatedDate() {
57
+        return createdDate;
58
+    }
59
+
60
+    public void setCreatedDate(Instant createdDate) {
61
+        this.createdDate = createdDate;
62
+    }
63
+
64
+    public String getLastModifiedBy() {
65
+        return lastModifiedBy;
66
+    }
67
+
68
+    public void setLastModifiedBy(String lastModifiedBy) {
69
+        this.lastModifiedBy = lastModifiedBy;
70
+    }
71
+
72
+    public Instant getLastModifiedDate() {
73
+        return lastModifiedDate;
74
+    }
75
+
76
+    public void setLastModifiedDate(Instant lastModifiedDate) {
77
+        this.lastModifiedDate = lastModifiedDate;
78
+    }
79
+}

+ 62
- 0
src/main/java/io/github/jhipster/application/domain/Authority.java 查看文件

@@ -0,0 +1,62 @@
1
+package io.github.jhipster.application.domain;
2
+
3
+import org.hibernate.annotations.Cache;
4
+import org.hibernate.annotations.CacheConcurrencyStrategy;
5
+import javax.persistence.Entity;
6
+import javax.persistence.Id;
7
+import javax.persistence.Table;
8
+import javax.persistence.Column;
9
+import javax.validation.constraints.NotNull;
10
+import javax.validation.constraints.Size;
11
+import java.io.Serializable;
12
+
13
+/**
14
+ * An authority (a security role) used by Spring Security.
15
+ */
16
+@Entity
17
+@Table(name = "jhi_authority")
18
+@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
19
+public class Authority implements Serializable {
20
+
21
+    private static final long serialVersionUID = 1L;
22
+
23
+    @NotNull
24
+    @Size(max = 50)
25
+    @Id
26
+    @Column(length = 50)
27
+    private String name;
28
+
29
+    public String getName() {
30
+        return name;
31
+    }
32
+
33
+    public void setName(String name) {
34
+        this.name = name;
35
+    }
36
+
37
+    @Override
38
+    public boolean equals(Object o) {
39
+        if (this == o) {
40
+            return true;
41
+        }
42
+        if (o == null || getClass() != o.getClass()) {
43
+            return false;
44
+        }
45
+
46
+        Authority authority = (Authority) o;
47
+
48
+        return !(name != null ? !name.equals(authority.name) : authority.name != null);
49
+    }
50
+
51
+    @Override
52
+    public int hashCode() {
53
+        return name != null ? name.hashCode() : 0;
54
+    }
55
+
56
+    @Override
57
+    public String toString() {
58
+        return "Authority{" +
59
+            "name='" + name + '\'' +
60
+            "}";
61
+    }
62
+}

+ 110
- 0
src/main/java/io/github/jhipster/application/domain/PersistentAuditEvent.java 查看文件

@@ -0,0 +1,110 @@
1
+package io.github.jhipster.application.domain;
2
+
3
+import javax.persistence.*;
4
+import javax.validation.constraints.NotNull;
5
+import java.io.Serializable;
6
+import java.time.Instant;
7
+import java.util.HashMap;
8
+import java.util.Objects;
9
+import java.util.Map;
10
+
11
+/**
12
+ * Persist AuditEvent managed by the Spring Boot actuator.
13
+ *
14
+ * @see org.springframework.boot.actuate.audit.AuditEvent
15
+ */
16
+@Entity
17
+@Table(name = "jhi_persistent_audit_event")
18
+public class PersistentAuditEvent implements Serializable {
19
+
20
+    private static final long serialVersionUID = 1L;
21
+
22
+    @Id
23
+    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
24
+    @SequenceGenerator(name = "sequenceGenerator")
25
+    @Column(name = "event_id")
26
+    private Long id;
27
+
28
+    @NotNull
29
+    @Column(nullable = false)
30
+    private String principal;
31
+
32
+    @Column(name = "event_date")
33
+    private Instant auditEventDate;
34
+
35
+    @Column(name = "event_type")
36
+    private String auditEventType;
37
+
38
+    @ElementCollection
39
+    @MapKeyColumn(name = "name")
40
+    @Column(name = "value")
41
+    @CollectionTable(name = "jhi_persistent_audit_evt_data", joinColumns=@JoinColumn(name="event_id"))
42
+    private Map<String, String> data = new HashMap<>();
43
+
44
+    public Long getId() {
45
+        return id;
46
+    }
47
+
48
+    public void setId(Long id) {
49
+        this.id = id;
50
+    }
51
+
52
+    public String getPrincipal() {
53
+        return principal;
54
+    }
55
+
56
+    public void setPrincipal(String principal) {
57
+        this.principal = principal;
58
+    }
59
+
60
+    public Instant getAuditEventDate() {
61
+        return auditEventDate;
62
+    }
63
+
64
+    public void setAuditEventDate(Instant auditEventDate) {
65
+        this.auditEventDate = auditEventDate;
66
+    }
67
+
68
+    public String getAuditEventType() {
69
+        return auditEventType;
70
+    }
71
+
72
+    public void setAuditEventType(String auditEventType) {
73
+        this.auditEventType = auditEventType;
74
+    }
75
+
76
+    public Map<String, String> getData() {
77
+        return data;
78
+    }
79
+
80
+    public void setData(Map<String, String> data) {
81
+        this.data = data;
82
+    }
83
+
84
+    @Override
85
+    public boolean equals(Object o) {
86
+        if (this == o) {
87
+            return true;
88
+        }
89
+        if (o == null || getClass() != o.getClass()) {
90
+            return false;
91
+        }
92
+
93
+        PersistentAuditEvent persistentAuditEvent = (PersistentAuditEvent) o;
94
+        return !(persistentAuditEvent.getId() == null || getId() == null) && Objects.equals(getId(), persistentAuditEvent.getId());
95
+    }
96
+
97
+    @Override
98
+    public int hashCode() {
99
+        return Objects.hashCode(getId());
100
+    }
101
+
102
+    @Override
103
+    public String toString() {
104
+        return "PersistentAuditEvent{" +
105
+            "principal='" + principal + '\'' +
106
+            ", auditEventDate=" + auditEventDate +
107
+            ", auditEventType='" + auditEventType + '\'' +
108
+            '}';
109
+    }
110
+}

+ 235
- 0
src/main/java/io/github/jhipster/application/domain/User.java 查看文件

@@ -0,0 +1,235 @@
1
+package io.github.jhipster.application.domain;
2
+
3
+import io.github.jhipster.application.config.Constants;
4
+
5
+import com.fasterxml.jackson.annotation.JsonIgnore;
6
+import org.apache.commons.lang3.StringUtils;
7
+import org.hibernate.annotations.BatchSize;
8
+import org.hibernate.annotations.Cache;
9
+import org.hibernate.annotations.CacheConcurrencyStrategy;
10
+import javax.validation.constraints.Email;
11
+
12
+import javax.persistence.*;
13
+import javax.validation.constraints.NotNull;
14
+import javax.validation.constraints.Pattern;
15
+import javax.validation.constraints.Size;
16
+import java.io.Serializable;
17
+import java.util.HashSet;
18
+import java.util.Locale;
19
+import java.util.Objects;
20
+import java.util.Set;
21
+import java.time.Instant;
22
+
23
+/**
24
+ * A user.
25
+ */
26
+@Entity
27
+@Table(name = "jhi_user")
28
+@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
29
+@org.springframework.data.elasticsearch.annotations.Document(indexName = "user")
30
+public class User extends AbstractAuditingEntity implements Serializable {
31
+
32
+    private static final long serialVersionUID = 1L;
33
+
34
+    @Id
35
+    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
36
+    @SequenceGenerator(name = "sequenceGenerator")
37
+    private Long id;
38
+
39
+    @NotNull
40
+    @Pattern(regexp = Constants.LOGIN_REGEX)
41
+    @Size(min = 1, max = 50)
42
+    @Column(length = 50, unique = true, nullable = false)
43
+    private String login;
44
+
45
+    @JsonIgnore
46
+    @NotNull
47
+    @Size(min = 60, max = 60)
48
+    @Column(name = "password_hash", length = 60, nullable = false)
49
+    private String password;
50
+
51
+    @Size(max = 50)
52
+    @Column(name = "first_name", length = 50)
53
+    private String firstName;
54
+
55
+    @Size(max = 50)
56
+    @Column(name = "last_name", length = 50)
57
+    private String lastName;
58
+
59
+    @Email
60
+    @Size(min = 5, max = 254)
61
+    @Column(length = 254, unique = true)
62
+    private String email;
63
+
64
+    @NotNull
65
+    @Column(nullable = false)
66
+    private boolean activated = false;
67
+
68
+    @Size(min = 2, max = 6)
69
+    @Column(name = "lang_key", length = 6)
70
+    private String langKey;
71
+
72
+    @Size(max = 256)
73
+    @Column(name = "image_url", length = 256)
74
+    private String imageUrl;
75
+
76
+    @Size(max = 20)
77
+    @Column(name = "activation_key", length = 20)
78
+    @JsonIgnore
79
+    private String activationKey;
80
+
81
+    @Size(max = 20)
82
+    @Column(name = "reset_key", length = 20)
83
+    @JsonIgnore
84
+    private String resetKey;
85
+
86
+    @Column(name = "reset_date")
87
+    private Instant resetDate = null;
88
+
89
+    @JsonIgnore
90
+    @ManyToMany
91
+    @JoinTable(
92
+        name = "jhi_user_authority",
93
+        joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
94
+        inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "name")})
95
+    @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
96
+    @BatchSize(size = 20)
97
+    private Set<Authority> authorities = new HashSet<>();
98
+
99
+    public Long getId() {
100
+        return id;
101
+    }
102
+
103
+    public void setId(Long id) {
104
+        this.id = id;
105
+    }
106
+
107
+    public String getLogin() {
108
+        return login;
109
+    }
110
+
111
+    // Lowercase the login before saving it in database
112
+    public void setLogin(String login) {
113
+        this.login = StringUtils.lowerCase(login, Locale.ENGLISH);
114
+    }
115
+
116
+    public String getPassword() {
117
+        return password;
118
+    }
119
+
120
+    public void setPassword(String password) {
121
+        this.password = password;
122
+    }
123
+
124
+    public String getFirstName() {
125
+        return firstName;
126
+    }
127
+
128
+    public void setFirstName(String firstName) {
129
+        this.firstName = firstName;
130
+    }
131
+
132
+    public String getLastName() {
133
+        return lastName;
134
+    }
135
+
136
+    public void setLastName(String lastName) {
137
+        this.lastName = lastName;
138
+    }
139
+
140
+    public String getEmail() {
141
+        return email;
142
+    }
143
+
144
+    public void setEmail(String email) {
145
+        this.email = email;
146
+    }
147
+
148
+    public String getImageUrl() {
149
+        return imageUrl;
150
+    }
151
+
152
+    public void setImageUrl(String imageUrl) {
153
+        this.imageUrl = imageUrl;
154
+    }
155
+
156
+    public boolean getActivated() {
157
+        return activated;
158
+    }
159
+
160
+    public void setActivated(boolean activated) {
161
+        this.activated = activated;
162
+    }
163
+
164
+    public String getActivationKey() {
165
+        return activationKey;
166
+    }
167
+
168
+    public void setActivationKey(String activationKey) {
169
+        this.activationKey = activationKey;
170
+    }
171
+
172
+    public String getResetKey() {
173
+        return resetKey;
174
+    }
175
+
176
+    public void setResetKey(String resetKey) {
177
+        this.resetKey = resetKey;
178
+    }
179
+
180
+    public Instant getResetDate() {
181
+        return resetDate;
182
+    }
183
+
184
+    public void setResetDate(Instant resetDate) {
185
+        this.resetDate = resetDate;
186
+    }
187
+
188
+    public String getLangKey() {
189
+        return langKey;
190
+    }
191
+
192
+    public void setLangKey(String langKey) {
193
+        this.langKey = langKey;
194
+    }
195
+
196
+    public Set<Authority> getAuthorities() {
197
+        return authorities;
198
+    }
199
+
200
+    public void setAuthorities(Set<Authority> authorities) {
201
+        this.authorities = authorities;
202
+    }
203
+
204
+    @Override
205
+    public boolean equals(Object o) {
206
+        if (this == o) {
207
+            return true;
208
+        }
209
+        if (o == null || getClass() != o.getClass()) {
210
+            return false;
211
+        }
212
+
213
+        User user = (User) o;
214
+        return !(user.getId() == null || getId() == null) && Objects.equals(getId(), user.getId());
215
+    }
216
+
217
+    @Override
218
+    public int hashCode() {
219
+        return Objects.hashCode(getId());
220
+    }
221
+
222
+    @Override
223
+    public String toString() {
224
+        return "User{" +
225
+            "login='" + login + '\'' +
226
+            ", firstName='" + firstName + '\'' +
227
+            ", lastName='" + lastName + '\'' +
228
+            ", email='" + email + '\'' +
229
+            ", imageUrl='" + imageUrl + '\'' +
230
+            ", activated='" + activated + '\'' +
231
+            ", langKey='" + langKey + '\'' +
232
+            ", activationKey='" + activationKey + '\'' +
233
+            "}";
234
+    }
235
+}

+ 4
- 0
src/main/java/io/github/jhipster/application/domain/package-info.java 查看文件

@@ -0,0 +1,4 @@
1
+/**
2
+ * JPA domain objects.
3
+ */
4
+package io.github.jhipster.application.domain;

+ 11
- 0
src/main/java/io/github/jhipster/application/repository/AuthorityRepository.java 查看文件

@@ -0,0 +1,11 @@
1
+package io.github.jhipster.application.repository;
2
+
3
+import io.github.jhipster.application.domain.Authority;
4
+
5
+import org.springframework.data.jpa.repository.JpaRepository;
6
+
7
+/**
8
+ * Spring Data JPA repository for the Authority entity.
9
+ */
10
+public interface AuthorityRepository extends JpaRepository<Authority, String> {
11
+}

+ 89
- 0
src/main/java/io/github/jhipster/application/repository/CustomAuditEventRepository.java 查看文件

@@ -0,0 +1,89 @@
1
+package io.github.jhipster.application.repository;
2
+
3
+import io.github.jhipster.application.config.Constants;
4
+import io.github.jhipster.application.config.audit.AuditEventConverter;
5
+import io.github.jhipster.application.domain.PersistentAuditEvent;
6
+
7
+import org.slf4j.Logger;
8
+import org.slf4j.LoggerFactory;
9
+import org.springframework.boot.actuate.audit.AuditEvent;
10
+import org.springframework.boot.actuate.audit.AuditEventRepository;
11
+import org.springframework.stereotype.Repository;
12
+import org.springframework.transaction.annotation.Propagation;
13
+import org.springframework.transaction.annotation.Transactional;
14
+
15
+import java.time.Instant;
16
+import java.util.*;
17
+
18
+/**
19
+ * An implementation of Spring Boot's AuditEventRepository.
20
+ */
21
+@Repository
22
+public class CustomAuditEventRepository implements AuditEventRepository {
23
+
24
+    private static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE";
25
+
26
+    /**
27
+     * Should be the same as in Liquibase migration.
28
+     */
29
+    protected static final int EVENT_DATA_COLUMN_MAX_LENGTH = 255;
30
+
31
+    private final PersistenceAuditEventRepository persistenceAuditEventRepository;
32
+
33
+    private final AuditEventConverter auditEventConverter;
34
+
35
+    private final Logger log = LoggerFactory.getLogger(getClass());
36
+
37
+    public CustomAuditEventRepository(PersistenceAuditEventRepository persistenceAuditEventRepository,
38
+            AuditEventConverter auditEventConverter) {
39
+
40
+        this.persistenceAuditEventRepository = persistenceAuditEventRepository;
41
+        this.auditEventConverter = auditEventConverter;
42
+    }
43
+
44
+    @Override
45
+    public List<AuditEvent> find(String principal, Instant after, String type) {
46
+        Iterable<PersistentAuditEvent> persistentAuditEvents =
47
+            persistenceAuditEventRepository.findByPrincipalAndAuditEventDateAfterAndAuditEventType(principal, after, type);
48
+        return auditEventConverter.convertToAuditEvent(persistentAuditEvents);
49
+    }
50
+
51
+    @Override
52
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
53
+    public void add(AuditEvent event) {
54
+        if (!AUTHORIZATION_FAILURE.equals(event.getType()) &&
55
+            !Constants.ANONYMOUS_USER.equals(event.getPrincipal())) {
56
+
57
+            PersistentAuditEvent persistentAuditEvent = new PersistentAuditEvent();
58
+            persistentAuditEvent.setPrincipal(event.getPrincipal());
59
+            persistentAuditEvent.setAuditEventType(event.getType());
60
+            persistentAuditEvent.setAuditEventDate(event.getTimestamp());
61
+            Map<String, String> eventData = auditEventConverter.convertDataToStrings(event.getData());
62
+            persistentAuditEvent.setData(truncate(eventData));
63
+            persistenceAuditEventRepository.save(persistentAuditEvent);
64
+        }
65
+    }
66
+
67
+    /**
68
+     * Truncate event data that might exceed column length.
69
+     */
70
+    private Map<String, String> truncate(Map<String, String> data) {
71
+        Map<String, String> results = new HashMap<>();
72
+
73
+        if (data != null) {
74
+            for (Map.Entry<String, String> entry : data.entrySet()) {
75
+                String value = entry.getValue();
76
+                if (value != null) {
77
+                    int length = value.length();
78
+                    if (length > EVENT_DATA_COLUMN_MAX_LENGTH) {
79
+                        value = value.substring(0, EVENT_DATA_COLUMN_MAX_LENGTH);
80
+                        log.warn("Event data for {} too long ({}) has been truncated to {}. Consider increasing column width.",
81
+                                 entry.getKey(), length, EVENT_DATA_COLUMN_MAX_LENGTH);
82
+                    }
83
+                }
84
+                results.put(entry.getKey(), value);
85
+            }
86
+        }
87
+        return results;
88
+    }
89
+}

+ 25
- 0
src/main/java/io/github/jhipster/application/repository/PersistenceAuditEventRepository.java 查看文件

@@ -0,0 +1,25 @@
1
+package io.github.jhipster.application.repository;
2
+
3
+import io.github.jhipster.application.domain.PersistentAuditEvent;
4
+import org.springframework.data.domain.Page;
5
+import org.springframework.data.domain.Pageable;
6
+import org.springframework.data.jpa.repository.JpaRepository;
7
+
8
+import java.time.Instant;
9
+import java.util.List;
10
+
11
+/**
12
+ * Spring Data JPA repository for the PersistentAuditEvent entity.
13
+ */
14
+public interface PersistenceAuditEventRepository extends JpaRepository<PersistentAuditEvent, Long> {
15
+
16
+    List<PersistentAuditEvent> findByPrincipal(String principal);
17
+
18
+    List<PersistentAuditEvent> findByAuditEventDateAfter(Instant after);
19
+
20
+    List<PersistentAuditEvent> findByPrincipalAndAuditEventDateAfter(String principal, Instant after);
21
+
22
+    List<PersistentAuditEvent> findByPrincipalAndAuditEventDateAfterAndAuditEventType(String principal, Instant after, String type);
23
+
24
+    Page<PersistentAuditEvent> findAllByAuditEventDateBetween(Instant fromDate, Instant toDate, Pageable pageable);
25
+}

+ 47
- 0
src/main/java/io/github/jhipster/application/repository/UserRepository.java 查看文件

@@ -0,0 +1,47 @@
1
+package io.github.jhipster.application.repository;
2
+
3
+import io.github.jhipster.application.domain.User;
4
+
5
+import org.springframework.cache.annotation.Cacheable;
6
+import org.springframework.data.domain.Page;
7
+import org.springframework.data.domain.Pageable;
8
+import org.springframework.data.jpa.repository.EntityGraph;
9
+import org.springframework.data.jpa.repository.JpaRepository;
10
+import org.springframework.stereotype.Repository;
11
+import java.util.List;
12
+import java.util.Optional;
13
+import java.time.Instant;
14
+
15
+/**
16
+ * Spring Data JPA repository for the User entity.
17
+ */
18
+@Repository
19
+public interface UserRepository extends JpaRepository<User, Long> {
20
+
21
+    String USERS_BY_LOGIN_CACHE = "usersByLogin";
22
+
23
+    String USERS_BY_EMAIL_CACHE = "usersByEmail";
24
+
25
+    Optional<User> findOneByActivationKey(String activationKey);
26
+
27
+    List<User> findAllByActivatedIsFalseAndCreatedDateBefore(Instant dateTime);
28
+
29
+    Optional<User> findOneByResetKey(String resetKey);
30
+
31
+    Optional<User> findOneByEmailIgnoreCase(String email);
32
+
33
+    Optional<User> findOneByLogin(String login);
34
+
35
+    @EntityGraph(attributePaths = "authorities")
36
+    Optional<User> findOneWithAuthoritiesById(Long id);
37
+
38
+    @EntityGraph(attributePaths = "authorities")
39
+    @Cacheable(cacheNames = USERS_BY_LOGIN_CACHE)
40
+    Optional<User> findOneWithAuthoritiesByLogin(String login);
41
+
42
+    @EntityGraph(attributePaths = "authorities")
43
+    @Cacheable(cacheNames = USERS_BY_EMAIL_CACHE)
44
+    Optional<User> findOneWithAuthoritiesByEmail(String email);
45
+
46
+    Page<User> findAllByLoginNot(Pageable pageable, String login);
47
+}

+ 4
- 0
src/main/java/io/github/jhipster/application/repository/package-info.java 查看文件

@@ -0,0 +1,4 @@
1
+/**
2
+ * Spring Data JPA repositories.
3
+ */
4
+package io.github.jhipster.application.repository;

+ 10
- 0
src/main/java/io/github/jhipster/application/repository/search/UserSearchRepository.java 查看文件

@@ -0,0 +1,10 @@
1
+package io.github.jhipster.application.repository.search;
2
+
3
+import io.github.jhipster.application.domain.User;
4
+import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
5
+
6
+/**
7
+ * Spring Data Elasticsearch repository for the User entity.
8
+ */
9
+public interface UserSearchRepository extends ElasticsearchRepository<User, Long> {
10
+}

+ 4
- 0
src/main/java/io/github/jhipster/application/repository/search/package-info.java 查看文件

@@ -0,0 +1,4 @@
1
+/**
2
+ * Spring Data Elasticsearch repositories.
3
+ */
4
+package io.github.jhipster.application.repository.search;

+ 16
- 0
src/main/java/io/github/jhipster/application/security/AuthoritiesConstants.java 查看文件

@@ -0,0 +1,16 @@
1
+package io.github.jhipster.application.security;
2
+
3
+/**
4
+ * Constants for Spring Security authorities.
5
+ */
6
+public final class AuthoritiesConstants {
7
+
8
+    public static final String ADMIN = "ROLE_ADMIN";
9
+
10
+    public static final String USER = "ROLE_USER";
11
+
12
+    public static final String ANONYMOUS = "ROLE_ANONYMOUS";
13
+
14
+    private AuthoritiesConstants() {
15
+    }
16
+}

+ 62
- 0
src/main/java/io/github/jhipster/application/security/DomainUserDetailsService.java 查看文件

@@ -0,0 +1,62 @@
1
+package io.github.jhipster.application.security;
2
+
3
+import io.github.jhipster.application.domain.User;
4
+import io.github.jhipster.application.repository.UserRepository;
5
+import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator;
6
+import org.slf4j.Logger;
7
+import org.slf4j.LoggerFactory;
8
+import org.springframework.security.core.GrantedAuthority;
9
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
10
+import org.springframework.security.core.userdetails.UserDetails;
11
+import org.springframework.security.core.userdetails.UserDetailsService;
12
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
13
+import org.springframework.stereotype.Component;
14
+import org.springframework.transaction.annotation.Transactional;
15
+
16
+import java.util.*;
17
+import java.util.stream.Collectors;
18
+
19
+/**
20
+ * Authenticate a user from the database.
21
+ */
22
+@Component("userDetailsService")
23
+public class DomainUserDetailsService implements UserDetailsService {
24
+
25
+    private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class);
26
+
27
+    private final UserRepository userRepository;
28
+
29
+    public DomainUserDetailsService(UserRepository userRepository) {
30
+        this.userRepository = userRepository;
31
+    }
32
+
33
+    @Override
34
+    @Transactional
35
+    public UserDetails loadUserByUsername(final String login) {
36
+        log.debug("Authenticating {}", login);
37
+
38
+        if (new EmailValidator().isValid(login, null)) {
39
+            return userRepository.findOneWithAuthoritiesByEmail(login)
40
+                .map(user -> createSpringSecurityUser(login, user))
41
+                .orElseThrow(() -> new UsernameNotFoundException("User with email " + login + " was not found in the database"));
42
+        }
43
+
44
+        String lowercaseLogin = login.toLowerCase(Locale.ENGLISH);
45
+        return userRepository.findOneWithAuthoritiesByLogin(lowercaseLogin)
46
+            .map(user -> createSpringSecurityUser(lowercaseLogin, user))
47
+            .orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the database"));
48
+
49
+    }
50
+
51
+    private org.springframework.security.core.userdetails.User createSpringSecurityUser(String lowercaseLogin, User user) {
52
+        if (!user.getActivated()) {
53
+            throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated");
54
+        }
55
+        List<GrantedAuthority> grantedAuthorities = user.getAuthorities().stream()
56
+            .map(authority -> new SimpleGrantedAuthority(authority.getName()))
57
+            .collect(Collectors.toList());
58
+        return new org.springframework.security.core.userdetails.User(user.getLogin(),
59
+            user.getPassword(),
60
+            grantedAuthorities);
61
+    }
62
+}

+ 76
- 0
src/main/java/io/github/jhipster/application/security/SecurityUtils.java 查看文件

@@ -0,0 +1,76 @@
1
+package io.github.jhipster.application.security;
2
+
3
+import org.springframework.security.core.context.SecurityContext;
4
+import org.springframework.security.core.context.SecurityContextHolder;
5
+import org.springframework.security.core.userdetails.UserDetails;
6
+
7
+import java.util.Optional;
8
+
9
+/**
10
+ * Utility class for Spring Security.
11
+ */
12
+public final class SecurityUtils {
13
+
14
+    private SecurityUtils() {
15
+    }
16
+
17
+    /**
18
+     * Get the login of the current user.
19
+     *
20
+     * @return the login of the current user
21
+     */
22
+    public static Optional<String> getCurrentUserLogin() {
23
+        SecurityContext securityContext = SecurityContextHolder.getContext();
24
+        return Optional.ofNullable(securityContext.getAuthentication())
25
+            .map(authentication -> {
26
+                if (authentication.getPrincipal() instanceof UserDetails) {
27
+                    UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
28
+                    return springSecurityUser.getUsername();
29
+                } else if (authentication.getPrincipal() instanceof String) {
30
+                    return (String) authentication.getPrincipal();
31
+                }
32
+                return null;
33
+            });
34
+    }
35
+
36
+    /**
37
+     * Get the JWT of the current user.
38
+     *
39
+     * @return the JWT of the current user
40
+     */
41
+    public static Optional<String> getCurrentUserJWT() {
42
+        SecurityContext securityContext = SecurityContextHolder.getContext();
43
+        return Optional.ofNullable(securityContext.getAuthentication())
44
+            .filter(authentication -> authentication.getCredentials() instanceof String)
45
+            .map(authentication -> (String) authentication.getCredentials());
46
+    }
47
+
48
+    /**
49
+     * Check if a user is authenticated.
50
+     *
51
+     * @return true if the user is authenticated, false otherwise
52
+     */
53
+    public static boolean isAuthenticated() {
54
+        SecurityContext securityContext = SecurityContextHolder.getContext();
55
+        return Optional.ofNullable(securityContext.getAuthentication())
56
+            .map(authentication -> authentication.getAuthorities().stream()
57
+                .noneMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(AuthoritiesConstants.ANONYMOUS)))
58
+            .orElse(false);
59
+    }
60
+
61
+    /**
62
+     * If the current user has a specific authority (security role).
63
+     * <p>
64
+     * The name of this method comes from the isUserInRole() method in the Servlet API
65
+     *
66
+     * @param authority the authority to check
67
+     * @return true if the current user has the authority, false otherwise
68
+     */
69
+    public static boolean isCurrentUserInRole(String authority) {
70
+        SecurityContext securityContext = SecurityContextHolder.getContext();
71
+        return Optional.ofNullable(securityContext.getAuthentication())
72
+            .map(authentication -> authentication.getAuthorities().stream()
73
+                .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(authority)))
74
+            .orElse(false);
75
+    }
76
+}

+ 20
- 0
src/main/java/io/github/jhipster/application/security/SpringSecurityAuditorAware.java 查看文件

@@ -0,0 +1,20 @@
1
+package io.github.jhipster.application.security;
2
+
3
+import io.github.jhipster.application.config.Constants;
4
+
5
+import java.util.Optional;
6
+
7
+import org.springframework.data.domain.AuditorAware;
8
+import org.springframework.stereotype.Component;
9
+
10
+/**
11
+ * Implementation of AuditorAware based on Spring Security.
12
+ */
13
+@Component
14
+public class SpringSecurityAuditorAware implements AuditorAware<String> {
15
+
16
+    @Override
17
+    public Optional<String> getCurrentAuditor() {
18
+        return Optional.of(SecurityUtils.getCurrentUserLogin().orElse(Constants.SYSTEM_ACCOUNT));
19
+    }
20
+}

+ 19
- 0
src/main/java/io/github/jhipster/application/security/UserNotActivatedException.java 查看文件

@@ -0,0 +1,19 @@
1
+package io.github.jhipster.application.security;
2
+
3
+import org.springframework.security.core.AuthenticationException;
4
+
5
+/**
6
+ * This exception is thrown in case of a not activated user trying to authenticate.
7
+ */
8
+public class UserNotActivatedException extends AuthenticationException {
9
+
10
+    private static final long serialVersionUID = 1L;
11
+
12
+    public UserNotActivatedException(String message) {
13
+        super(message);
14
+    }
15
+
16
+    public UserNotActivatedException(String message, Throwable t) {
17
+        super(message, t);
18
+    }
19
+}

+ 21
- 0
src/main/java/io/github/jhipster/application/security/jwt/JWTConfigurer.java 查看文件

@@ -0,0 +1,21 @@
1
+package io.github.jhipster.application.security.jwt;
2
+
3
+import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
4
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
5
+import org.springframework.security.web.DefaultSecurityFilterChain;
6
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
7
+
8
+public class JWTConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
9
+
10
+    private TokenProvider tokenProvider;
11
+
12
+    public JWTConfigurer(TokenProvider tokenProvider) {
13
+        this.tokenProvider = tokenProvider;
14
+    }
15
+
16
+    @Override
17
+    public void configure(HttpSecurity http) throws Exception {
18
+        JWTFilter customFilter = new JWTFilter(tokenProvider);
19
+        http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
20
+    }
21
+}

+ 54
- 0
src/main/java/io/github/jhipster/application/security/jwt/JWTFilter.java 查看文件

@@ -0,0 +1,54 @@
1
+package io.github.jhipster.application.security.jwt;
2
+
3
+import org.springframework.security.core.Authentication;
4
+import org.springframework.security.core.context.SecurityContextHolder;
5
+import org.springframework.util.StringUtils;
6
+import org.springframework.web.filter.GenericFilterBean;
7
+
8
+import javax.servlet.FilterChain;
9
+import javax.servlet.ServletException;
10
+import javax.servlet.ServletRequest;
11
+import javax.servlet.ServletResponse;
12
+import javax.servlet.http.HttpServletRequest;
13
+import java.io.IOException;
14
+
15
+/**
16
+ * Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is
17
+ * found.
18
+ */
19
+public class JWTFilter extends GenericFilterBean {
20
+
21
+    public static final String AUTHORIZATION_HEADER = "Authorization";
22
+
23
+    public static final String AUTHORIZATION_TOKEN = "access_token";
24
+
25
+    private TokenProvider tokenProvider;
26
+
27
+    public JWTFilter(TokenProvider tokenProvider) {
28
+        this.tokenProvider = tokenProvider;
29
+    }
30
+
31
+    @Override
32
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
33
+        throws IOException, ServletException {
34
+        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
35
+        String jwt = resolveToken(httpServletRequest);
36
+        if (StringUtils.hasText(jwt) && this.tokenProvider.validateToken(jwt)) {
37
+            Authentication authentication = this.tokenProvider.getAuthentication(jwt);
38
+            SecurityContextHolder.getContext().setAuthentication(authentication);
39
+        }
40
+        filterChain.doFilter(servletRequest, servletResponse);
41
+    }
42
+
43
+    private String resolveToken(HttpServletRequest request){
44
+        String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
45
+        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
46
+            return bearerToken.substring(7);
47
+        }
48
+        String jwt = request.getParameter(AUTHORIZATION_TOKEN);
49
+        if (StringUtils.hasText(jwt)) {
50
+            return jwt;
51
+        }
52
+        return null;
53
+    }
54
+}

+ 119
- 0
src/main/java/io/github/jhipster/application/security/jwt/TokenProvider.java 查看文件

@@ -0,0 +1,119 @@
1
+package io.github.jhipster.application.security.jwt;
2
+
3
+import java.nio.charset.StandardCharsets;
4
+import java.security.Key;
5
+import java.util.*;
6
+import java.util.stream.Collectors;
7
+import javax.annotation.PostConstruct;
8
+
9
+import org.slf4j.Logger;
10
+import org.slf4j.LoggerFactory;
11
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
12
+import org.springframework.security.core.Authentication;
13
+import org.springframework.security.core.GrantedAuthority;
14
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
15
+import org.springframework.security.core.userdetails.User;
16
+import org.springframework.stereotype.Component;
17
+import org.springframework.util.StringUtils;
18
+
19
+import io.github.jhipster.config.JHipsterProperties;
20
+import io.jsonwebtoken.*;
21
+import io.jsonwebtoken.io.Decoders;
22
+import io.jsonwebtoken.security.Keys;
23
+
24
+@Component
25
+public class TokenProvider {
26
+
27
+    private final Logger log = LoggerFactory.getLogger(TokenProvider.class);
28
+
29
+    private static final String AUTHORITIES_KEY = "auth";
30
+
31
+    private Key key;
32
+
33
+    private long tokenValidityInMilliseconds;
34
+
35
+    private long tokenValidityInMillisecondsForRememberMe;
36
+
37
+    private final JHipsterProperties jHipsterProperties;
38
+
39
+    public TokenProvider(JHipsterProperties jHipsterProperties) {
40
+        this.jHipsterProperties = jHipsterProperties;
41
+    }
42
+
43
+    @PostConstruct
44
+    public void init() {
45
+        byte[] keyBytes;
46
+        String secret = jHipsterProperties.getSecurity().getAuthentication().getJwt().getSecret();
47
+        if (!StringUtils.isEmpty(secret)) {
48
+            log.warn("Warning: the JWT key used is not Base64-encoded. " +
49
+                "We recommend using the `jhipster.security.authentication.jwt.base64-secret` key for optimum security.");
50
+            keyBytes = secret.getBytes(StandardCharsets.UTF_8);
51
+        } else {
52
+            log.debug("Using a Base64-encoded JWT secret key");
53
+            keyBytes = Decoders.BASE64.decode(jHipsterProperties.getSecurity().getAuthentication().getJwt().getBase64Secret());
54
+        }
55
+        this.key = Keys.hmacShaKeyFor(keyBytes);
56
+        this.tokenValidityInMilliseconds =
57
+            1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSeconds();
58
+        this.tokenValidityInMillisecondsForRememberMe =
59
+            1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt()
60
+                .getTokenValidityInSecondsForRememberMe();
61
+    }
62
+
63
+    public String createToken(Authentication authentication, boolean rememberMe) {
64
+        String authorities = authentication.getAuthorities().stream()
65
+            .map(GrantedAuthority::getAuthority)
66
+            .collect(Collectors.joining(","));
67
+
68
+        long now = (new Date()).getTime();
69
+        Date validity;
70
+        if (rememberMe) {
71
+            validity = new Date(now + this.tokenValidityInMillisecondsForRememberMe);
72
+        } else {
73
+            validity = new Date(now + this.tokenValidityInMilliseconds);
74
+        }
75
+
76
+        return Jwts.builder()
77
+            .setSubject(authentication.getName())
78
+            .claim(AUTHORITIES_KEY, authorities)
79
+            .signWith(key, SignatureAlgorithm.HS512)
80
+            .setExpiration(validity)
81
+            .compact();
82
+    }
83
+
84
+    public Authentication getAuthentication(String token) {
85
+        Claims claims = Jwts.parser()
86
+            .setSigningKey(key)
87
+            .parseClaimsJws(token)
88
+            .getBody();
89
+
90
+        Collection<? extends GrantedAuthority> authorities =
91
+            Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
92
+                .map(SimpleGrantedAuthority::new)
93
+                .collect(Collectors.toList());
94
+
95
+        User principal = new User(claims.getSubject(), "", authorities);
96
+
97
+        return new UsernamePasswordAuthenticationToken(principal, token, authorities);
98
+    }
99
+
100
+    public boolean validateToken(String authToken) {
101
+        try {
102
+            Jwts.parser().setSigningKey(key).parseClaimsJws(authToken);
103
+            return true;
104
+        } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
105
+            log.info("Invalid JWT signature.");
106
+            log.trace("Invalid JWT signature trace: {}", e);
107
+        } catch (ExpiredJwtException e) {
108
+            log.info("Expired JWT token.");
109
+            log.trace("Expired JWT token trace: {}", e);
110
+        } catch (UnsupportedJwtException e) {
111
+            log.info("Unsupported JWT token.");
112
+            log.trace("Unsupported JWT token trace: {}", e);
113
+        } catch (IllegalArgumentException e) {
114
+            log.info("JWT token compact of handler are invalid.");
115
+            log.trace("JWT token compact of handler are invalid trace: {}", e);
116
+        }
117
+        return false;
118
+    }
119
+}

+ 4
- 0
src/main/java/io/github/jhipster/application/security/package-info.java 查看文件

@@ -0,0 +1,4 @@
1
+/**
2
+ * Spring Security configuration.
3
+ */
4
+package io.github.jhipster.application.security;

+ 51
- 0
src/main/java/io/github/jhipster/application/service/AuditEventService.java 查看文件

@@ -0,0 +1,51 @@
1
+package io.github.jhipster.application.service;
2
+
3
+import io.github.jhipster.application.config.audit.AuditEventConverter;
4
+import io.github.jhipster.application.repository.PersistenceAuditEventRepository;
5
+import org.springframework.boot.actuate.audit.AuditEvent;
6
+import org.springframework.data.domain.Page;
7
+import org.springframework.data.domain.Pageable;
8
+import org.springframework.stereotype.Service;
9
+import org.springframework.transaction.annotation.Transactional;
10
+
11
+import java.time.Instant;
12
+import java.util.Optional;
13
+
14
+/**
15
+ * Service for managing audit events.
16
+ * <p>
17
+ * This is the default implementation to support SpringBoot Actuator AuditEventRepository
18
+ */
19
+@Service
20
+@Transactional
21
+public class AuditEventService {
22
+
23
+    private final PersistenceAuditEventRepository persistenceAuditEventRepository;
24
+
25
+    private final AuditEventConverter auditEventConverter;
26
+
27
+    public AuditEventService(
28
+        PersistenceAuditEventRepository persistenceAuditEventRepository,
29
+        AuditEventConverter auditEventConverter) {
30
+
31
+        this.persistenceAuditEventRepository = persistenceAuditEventRepository;
32
+        this.auditEventConverter = auditEventConverter;
33
+    }
34
+
35
+    public Page<AuditEvent> findAll(Pageable pageable) {
36
+        return persistenceAuditEventRepository.findAll(pageable)
37
+            .map(auditEventConverter::convertToAuditEvent);
38
+    }
39
+
40
+    public Page<AuditEvent> findByDates(Instant fromDate, Instant toDate, Pageable pageable) {
41
+        return persistenceAuditEventRepository.findAllByAuditEventDateBetween(fromDate, toDate, pageable)
42
+            .map(auditEventConverter::convertToAuditEvent);
43
+    }
44
+
45
+    public Optional<AuditEvent> find(Long id) {
46
+        return Optional.ofNullable(persistenceAuditEventRepository.findById(id))
47
+            .filter(Optional::isPresent)
48
+            .map(Optional::get)
49
+            .map(auditEventConverter::convertToAuditEvent);
50
+    }
51
+}

+ 105
- 0
src/main/java/io/github/jhipster/application/service/MailService.java 查看文件

@@ -0,0 +1,105 @@
1
+package io.github.jhipster.application.service;
2
+
3
+import io.github.jhipster.application.domain.User;
4
+
5
+import io.github.jhipster.config.JHipsterProperties;
6
+
7
+import java.nio.charset.StandardCharsets;
8
+import java.util.Locale;
9
+import javax.mail.internet.MimeMessage;
10
+
11
+import org.slf4j.Logger;
12
+import org.slf4j.LoggerFactory;
13
+import org.springframework.context.MessageSource;
14
+import org.springframework.mail.javamail.JavaMailSender;
15
+import org.springframework.mail.javamail.MimeMessageHelper;
16
+import org.springframework.scheduling.annotation.Async;
17
+import org.springframework.stereotype.Service;
18
+import org.thymeleaf.context.Context;
19
+import org.thymeleaf.spring5.SpringTemplateEngine;
20
+
21
+/**
22
+ * Service for sending emails.
23
+ * <p>
24
+ * We use the @Async annotation to send emails asynchronously.
25
+ */
26
+@Service
27
+public class MailService {
28
+
29
+    private final Logger log = LoggerFactory.getLogger(MailService.class);
30
+
31
+    private static final String USER = "user";
32
+
33
+    private static final String BASE_URL = "baseUrl";
34
+
35
+    private final JHipsterProperties jHipsterProperties;
36
+
37
+    private final JavaMailSender javaMailSender;
38
+
39
+    private final MessageSource messageSource;
40
+
41
+    private final SpringTemplateEngine templateEngine;
42
+
43
+    public MailService(JHipsterProperties jHipsterProperties, JavaMailSender javaMailSender,
44
+            MessageSource messageSource, SpringTemplateEngine templateEngine) {
45
+
46
+        this.jHipsterProperties = jHipsterProperties;
47
+        this.javaMailSender = javaMailSender;
48
+        this.messageSource = messageSource;
49
+        this.templateEngine = templateEngine;
50
+    }
51
+
52
+    @Async
53
+    public void sendEmail(String to, String subject, String content, boolean isMultipart, boolean isHtml) {
54
+        log.debug("Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}",
55
+            isMultipart, isHtml, to, subject, content);
56
+
57
+        // Prepare message using a Spring helper
58
+        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
59
+        try {
60
+            MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, StandardCharsets.UTF_8.name());
61
+            message.setTo(to);
62
+            message.setFrom(jHipsterProperties.getMail().getFrom());
63
+            message.setSubject(subject);
64
+            message.setText(content, isHtml);
65
+            javaMailSender.send(mimeMessage);
66
+            log.debug("Sent email to User '{}'", to);
67
+        } catch (Exception e) {
68
+            if (log.isDebugEnabled()) {
69
+                log.warn("Email could not be sent to user '{}'", to, e);
70
+            } else {
71
+                log.warn("Email could not be sent to user '{}': {}", to, e.getMessage());
72
+            }
73
+        }
74
+    }
75
+
76
+    @Async
77
+    public void sendEmailFromTemplate(User user, String templateName, String titleKey) {
78
+        Locale locale = Locale.forLanguageTag(user.getLangKey());
79
+        Context context = new Context(locale);
80
+        context.setVariable(USER, user);
81
+        context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl());
82
+        String content = templateEngine.process(templateName, context);
83
+        String subject = messageSource.getMessage(titleKey, null, locale);
84
+        sendEmail(user.getEmail(), subject, content, false, true);
85
+
86
+    }
87
+
88
+    @Async
89
+    public void sendActivationEmail(User user) {
90
+        log.debug("Sending activation email to '{}'", user.getEmail());
91
+        sendEmailFromTemplate(user, "mail/activationEmail", "email.activation.title");
92
+    }
93
+
94
+    @Async
95
+    public void sendCreationEmail(User user) {
96
+        log.debug("Sending creation email to '{}'", user.getEmail());
97
+        sendEmailFromTemplate(user, "mail/creationEmail", "email.activation.title");
98
+    }
99
+
100
+    @Async
101
+    public void sendPasswordResetMail(User user) {
102
+        log.debug("Sending password reset email to '{}'", user.getEmail());
103
+        sendEmailFromTemplate(user, "mail/passwordResetEmail", "email.reset.title");
104
+    }
105
+}

+ 304
- 0
src/main/java/io/github/jhipster/application/service/UserService.java 查看文件

@@ -0,0 +1,304 @@
1
+package io.github.jhipster.application.service;
2
+
3
+import io.github.jhipster.application.config.Constants;
4
+import io.github.jhipster.application.domain.Authority;
5
+import io.github.jhipster.application.domain.User;
6
+import io.github.jhipster.application.repository.AuthorityRepository;
7
+import io.github.jhipster.application.repository.UserRepository;
8
+import io.github.jhipster.application.repository.search.UserSearchRepository;
9
+import io.github.jhipster.application.security.AuthoritiesConstants;
10
+import io.github.jhipster.application.security.SecurityUtils;
11
+import io.github.jhipster.application.service.dto.UserDTO;
12
+import io.github.jhipster.application.service.util.RandomUtil;
13
+import io.github.jhipster.application.web.rest.errors.*;
14
+
15
+import org.slf4j.Logger;
16
+import org.slf4j.LoggerFactory;
17
+import org.springframework.cache.CacheManager;
18
+import org.springframework.data.domain.Page;
19
+import org.springframework.data.domain.Pageable;
20
+import org.springframework.scheduling.annotation.Scheduled;
21
+import org.springframework.security.crypto.password.PasswordEncoder;
22
+import org.springframework.stereotype.Service;
23
+import org.springframework.transaction.annotation.Transactional;
24
+
25
+import java.time.Instant;
26
+import java.time.temporal.ChronoUnit;
27
+import java.util.*;
28
+import java.util.stream.Collectors;
29
+
30
+/**
31
+ * Service class for managing users.
32
+ */
33
+@Service
34
+@Transactional
35
+public class UserService {
36
+
37
+    private final Logger log = LoggerFactory.getLogger(UserService.class);
38
+
39
+    private final UserRepository userRepository;
40
+
41
+    private final PasswordEncoder passwordEncoder;
42
+
43
+    private final UserSearchRepository userSearchRepository;
44
+
45
+    private final AuthorityRepository authorityRepository;
46
+
47
+    private final CacheManager cacheManager;
48
+
49
+    public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, UserSearchRepository userSearchRepository, AuthorityRepository authorityRepository, CacheManager cacheManager) {
50
+        this.userRepository = userRepository;
51
+        this.passwordEncoder = passwordEncoder;
52
+        this.userSearchRepository = userSearchRepository;
53
+        this.authorityRepository = authorityRepository;
54
+        this.cacheManager = cacheManager;
55
+    }
56
+
57
+    public Optional<User> activateRegistration(String key) {
58
+        log.debug("Activating user for activation key {}", key);
59
+        return userRepository.findOneByActivationKey(key)
60
+            .map(user -> {
61
+                // activate given user for the registration key.
62
+                user.setActivated(true);
63
+                user.setActivationKey(null);
64
+                userSearchRepository.save(user);
65
+                this.clearUserCaches(user);
66
+                log.debug("Activated user: {}", user);
67
+                return user;
68
+            });
69
+    }
70
+
71
+    public Optional<User> completePasswordReset(String newPassword, String key) {
72
+        log.debug("Reset user password for reset key {}", key);
73
+        return userRepository.findOneByResetKey(key)
74
+            .filter(user -> user.getResetDate().isAfter(Instant.now().minusSeconds(86400)))
75
+            .map(user -> {
76
+                user.setPassword(passwordEncoder.encode(newPassword));
77
+                user.setResetKey(null);
78
+                user.setResetDate(null);
79
+                this.clearUserCaches(user);
80
+                return user;
81
+            });
82
+    }
83
+
84
+    public Optional<User> requestPasswordReset(String mail) {
85
+        return userRepository.findOneByEmailIgnoreCase(mail)
86
+            .filter(User::getActivated)
87
+            .map(user -> {
88
+                user.setResetKey(RandomUtil.generateResetKey());
89
+                user.setResetDate(Instant.now());
90
+                this.clearUserCaches(user);
91
+                return user;
92
+            });
93
+    }
94
+
95
+    public User registerUser(UserDTO userDTO, String password) {
96
+        userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()).ifPresent(existingUser -> {
97
+            boolean removed = removeNonActivatedUser(existingUser);
98
+            if (!removed) {
99
+                throw new LoginAlreadyUsedException();
100
+            }
101
+        });
102
+        userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()).ifPresent(existingUser -> {
103
+            boolean removed = removeNonActivatedUser(existingUser);
104
+            if (!removed) {
105
+                throw new EmailAlreadyUsedException();
106
+            }
107
+        });
108
+        User newUser = new User();
109
+        String encryptedPassword = passwordEncoder.encode(password);
110
+        newUser.setLogin(userDTO.getLogin().toLowerCase());
111
+        // new user gets initially a generated password
112
+        newUser.setPassword(encryptedPassword);
113
+        newUser.setFirstName(userDTO.getFirstName());
114
+        newUser.setLastName(userDTO.getLastName());
115
+        newUser.setEmail(userDTO.getEmail().toLowerCase());
116
+        newUser.setImageUrl(userDTO.getImageUrl());
117
+        newUser.setLangKey(userDTO.getLangKey());
118
+        // new user is not active
119
+        newUser.setActivated(false);
120
+        // new user gets registration key
121
+        newUser.setActivationKey(RandomUtil.generateActivationKey());
122
+        Set<Authority> authorities = new HashSet<>();
123
+        authorityRepository.findById(AuthoritiesConstants.USER).ifPresent(authorities::add);
124
+        newUser.setAuthorities(authorities);
125
+        userRepository.save(newUser);
126
+        userSearchRepository.save(newUser);
127
+        this.clearUserCaches(newUser);
128
+        log.debug("Created Information for User: {}", newUser);
129
+        return newUser;
130
+    }
131
+    private boolean removeNonActivatedUser(User existingUser){
132
+        if (existingUser.getActivated()) {
133
+             return false;
134
+        }
135
+        userRepository.delete(existingUser);
136
+        userRepository.flush();
137
+        this.clearUserCaches(existingUser);
138
+        return true;
139
+    }
140
+
141
+    public User createUser(UserDTO userDTO) {
142
+        User user = new User();
143
+        user.setLogin(userDTO.getLogin().toLowerCase());
144
+        user.setFirstName(userDTO.getFirstName());
145
+        user.setLastName(userDTO.getLastName());
146
+        user.setEmail(userDTO.getEmail().toLowerCase());
147
+        user.setImageUrl(userDTO.getImageUrl());
148
+        if (userDTO.getLangKey() == null) {
149
+            user.setLangKey(Constants.DEFAULT_LANGUAGE); // default language
150
+        } else {
151
+            user.setLangKey(userDTO.getLangKey());
152
+        }
153
+        String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword());
154
+        user.setPassword(encryptedPassword);
155
+        user.setResetKey(RandomUtil.generateResetKey());
156
+        user.setResetDate(Instant.now());
157
+        user.setActivated(true);
158
+        if (userDTO.getAuthorities() != null) {
159
+            Set<Authority> authorities = userDTO.getAuthorities().stream()
160
+                .map(authorityRepository::findById)
161
+                .filter(Optional::isPresent)
162
+                .map(Optional::get)
163
+                .collect(Collectors.toSet());
164
+            user.setAuthorities(authorities);
165
+        }
166
+        userRepository.save(user);
167
+        userSearchRepository.save(user);
168
+        this.clearUserCaches(user);
169
+        log.debug("Created Information for User: {}", user);
170
+        return user;
171
+    }
172
+
173
+    /**
174
+     * Update basic information (first name, last name, email, language) for the current user.
175
+     *
176
+     * @param firstName first name of user
177
+     * @param lastName last name of user
178
+     * @param email email id of user
179
+     * @param langKey language key
180
+     * @param imageUrl image URL of user
181
+     */
182
+    public void updateUser(String firstName, String lastName, String email, String langKey, String imageUrl) {
183
+        SecurityUtils.getCurrentUserLogin()
184
+            .flatMap(userRepository::findOneByLogin)
185
+            .ifPresent(user -> {
186
+                user.setFirstName(firstName);
187
+                user.setLastName(lastName);
188
+                user.setEmail(email.toLowerCase());
189
+                user.setLangKey(langKey);
190
+                user.setImageUrl(imageUrl);
191
+                userSearchRepository.save(user);
192
+                this.clearUserCaches(user);
193
+                log.debug("Changed Information for User: {}", user);
194
+            });
195
+    }
196
+
197
+    /**
198
+     * Update all information for a specific user, and return the modified user.
199
+     *
200
+     * @param userDTO user to update
201
+     * @return updated user
202
+     */
203
+    public Optional<UserDTO> updateUser(UserDTO userDTO) {
204
+        return Optional.of(userRepository
205
+            .findById(userDTO.getId()))
206
+            .filter(Optional::isPresent)
207
+            .map(Optional::get)
208
+            .map(user -> {
209
+                this.clearUserCaches(user);
210
+                user.setLogin(userDTO.getLogin().toLowerCase());
211
+                user.setFirstName(userDTO.getFirstName());
212
+                user.setLastName(userDTO.getLastName());
213
+                user.setEmail(userDTO.getEmail().toLowerCase());
214
+                user.setImageUrl(userDTO.getImageUrl());
215
+                user.setActivated(userDTO.isActivated());
216
+                user.setLangKey(userDTO.getLangKey());
217
+                Set<Authority> managedAuthorities = user.getAuthorities();
218
+                managedAuthorities.clear();
219
+                userDTO.getAuthorities().stream()
220
+                    .map(authorityRepository::findById)
221
+                    .filter(Optional::isPresent)
222
+                    .map(Optional::get)
223
+                    .forEach(managedAuthorities::add);
224
+                userSearchRepository.save(user);
225
+                this.clearUserCaches(user);
226
+                log.debug("Changed Information for User: {}", user);
227
+                return user;
228
+            })
229
+            .map(UserDTO::new);
230
+    }
231
+
232
+    public void deleteUser(String login) {
233
+        userRepository.findOneByLogin(login).ifPresent(user -> {
234
+            userRepository.delete(user);
235
+            userSearchRepository.delete(user);
236
+            this.clearUserCaches(user);
237
+            log.debug("Deleted User: {}", user);
238
+        });
239
+    }
240
+
241
+    public void changePassword(String currentClearTextPassword, String newPassword) {
242
+        SecurityUtils.getCurrentUserLogin()
243
+            .flatMap(userRepository::findOneByLogin)
244
+            .ifPresent(user -> {
245
+                String currentEncryptedPassword = user.getPassword();
246
+                if (!passwordEncoder.matches(currentClearTextPassword, currentEncryptedPassword)) {
247
+                    throw new InvalidPasswordException();
248
+                }
249
+                String encryptedPassword = passwordEncoder.encode(newPassword);
250
+                user.setPassword(encryptedPassword);
251
+                this.clearUserCaches(user);
252
+                log.debug("Changed password for User: {}", user);
253
+            });
254
+    }
255
+
256
+    @Transactional(readOnly = true)
257
+    public Page<UserDTO> getAllManagedUsers(Pageable pageable) {
258
+        return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER).map(UserDTO::new);
259
+    }
260
+
261
+    @Transactional(readOnly = true)
262
+    public Optional<User> getUserWithAuthoritiesByLogin(String login) {
263
+        return userRepository.findOneWithAuthoritiesByLogin(login);
264
+    }
265
+
266
+    @Transactional(readOnly = true)
267
+    public Optional<User> getUserWithAuthorities(Long id) {
268
+        return userRepository.findOneWithAuthoritiesById(id);
269
+    }
270
+
271
+    @Transactional(readOnly = true)
272
+    public Optional<User> getUserWithAuthorities() {
273
+        return SecurityUtils.getCurrentUserLogin().flatMap(userRepository::findOneWithAuthoritiesByLogin);
274
+    }
275
+
276
+    /**
277
+     * Not activated users should be automatically deleted after 3 days.
278
+     * <p>
279
+     * This is scheduled to get fired everyday, at 01:00 (am).
280
+     */
281
+    @Scheduled(cron = "0 0 1 * * ?")
282
+    public void removeNotActivatedUsers() {
283
+        userRepository
284
+            .findAllByActivatedIsFalseAndCreatedDateBefore(Instant.now().minus(3, ChronoUnit.DAYS))
285
+            .forEach(user -> {
286
+                log.debug("Deleting not activated user {}", user.getLogin());
287
+                userRepository.delete(user);
288
+                userSearchRepository.delete(user);
289
+                this.clearUserCaches(user);
290
+            });
291
+    }
292
+
293
+    /**
294
+     * @return a list of all the authorities
295
+     */
296
+    public List<String> getAuthorities() {
297
+        return authorityRepository.findAll().stream().map(Authority::getName).collect(Collectors.toList());
298
+    }
299
+
300
+    private void clearUserCaches(User user) {
301
+        Objects.requireNonNull(cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE)).evict(user.getLogin());
302
+        Objects.requireNonNull(cacheManager.getCache(UserRepository.USERS_BY_EMAIL_CACHE)).evict(user.getEmail());
303
+    }
304
+}

+ 35
- 0
src/main/java/io/github/jhipster/application/service/dto/PasswordChangeDTO.java 查看文件

@@ -0,0 +1,35 @@
1
+package io.github.jhipster.application.service.dto;
2
+
3
+/**
4
+ * A DTO representing a password change required data - current and new password.
5
+ */
6
+public class PasswordChangeDTO {
7
+    private String currentPassword;
8
+    private String newPassword;
9
+
10
+    public PasswordChangeDTO() {
11
+        // Empty constructor needed for Jackson.
12
+    }
13
+
14
+    public PasswordChangeDTO(String currentPassword, String newPassword) {
15
+        this.currentPassword = currentPassword;
16
+        this.newPassword = newPassword;
17
+    }
18
+
19
+    public String getCurrentPassword() {
20
+
21
+        return currentPassword;
22
+    }
23
+
24
+    public void setCurrentPassword(String currentPassword) {
25
+        this.currentPassword = currentPassword;
26
+    }
27
+
28
+    public String getNewPassword() {
29
+        return newPassword;
30
+    }
31
+
32
+    public void setNewPassword(String newPassword) {
33
+        this.newPassword = newPassword;
34
+    }
35
+}

+ 199
- 0
src/main/java/io/github/jhipster/application/service/dto/UserDTO.java 查看文件

@@ -0,0 +1,199 @@
1
+package io.github.jhipster.application.service.dto;
2
+
3
+import io.github.jhipster.application.config.Constants;
4
+
5
+import io.github.jhipster.application.domain.Authority;
6
+import io.github.jhipster.application.domain.User;
7
+
8
+import javax.validation.constraints.Email;
9
+import javax.validation.constraints.NotBlank;
10
+
11
+import javax.validation.constraints.*;
12
+import java.time.Instant;
13
+import java.util.Set;
14
+import java.util.stream.Collectors;
15
+
16
+/**
17
+ * A DTO representing a user, with his authorities.
18
+ */
19
+public class UserDTO {
20
+
21
+    private Long id;
22
+
23
+    @NotBlank
24
+    @Pattern(regexp = Constants.LOGIN_REGEX)
25
+    @Size(min = 1, max = 50)
26
+    private String login;
27
+
28
+    @Size(max = 50)
29
+    private String firstName;
30
+
31
+    @Size(max = 50)
32
+    private String lastName;
33
+
34
+    @Email
35
+    @Size(min = 5, max = 254)
36
+    private String email;
37
+
38
+    @Size(max = 256)
39
+    private String imageUrl;
40
+
41
+    private boolean activated = false;
42
+
43
+    @Size(min = 2, max = 6)
44
+    private String langKey;
45
+
46
+    private String createdBy;
47
+
48
+    private Instant createdDate;
49
+
50
+    private String lastModifiedBy;
51
+
52
+    private Instant lastModifiedDate;
53
+
54
+    private Set<String> authorities;
55
+
56
+    public UserDTO() {
57
+        // Empty constructor needed for Jackson.
58
+    }
59
+
60
+    public UserDTO(User user) {
61
+        this.id = user.getId();
62
+        this.login = user.getLogin();
63
+        this.firstName = user.getFirstName();
64
+        this.lastName = user.getLastName();
65
+        this.email = user.getEmail();
66
+        this.activated = user.getActivated();
67
+        this.imageUrl = user.getImageUrl();
68
+        this.langKey = user.getLangKey();
69
+        this.createdBy = user.getCreatedBy();
70
+        this.createdDate = user.getCreatedDate();
71
+        this.lastModifiedBy = user.getLastModifiedBy();
72
+        this.lastModifiedDate = user.getLastModifiedDate();
73
+        this.authorities = user.getAuthorities().stream()
74
+            .map(Authority::getName)
75
+            .collect(Collectors.toSet());
76
+    }
77
+
78
+    public Long getId() {
79
+        return id;
80
+    }
81
+
82
+    public void setId(Long id) {
83
+        this.id = id;
84
+    }
85
+
86
+    public String getLogin() {
87
+        return login;
88
+    }
89
+
90
+    public void setLogin(String login) {
91
+        this.login = login;
92
+    }
93
+
94
+    public String getFirstName() {
95
+        return firstName;
96
+    }
97
+
98
+    public void setFirstName(String firstName) {
99
+        this.firstName = firstName;
100
+    }
101
+
102
+    public String getLastName() {
103
+        return lastName;
104
+    }
105
+
106
+    public void setLastName(String lastName) {
107
+        this.lastName = lastName;
108
+    }
109
+
110
+    public String getEmail() {
111
+        return email;
112
+    }
113
+
114
+    public void setEmail(String email) {
115
+        this.email = email;
116
+    }
117
+
118
+    public String getImageUrl() {
119
+        return imageUrl;
120
+    }
121
+
122
+    public void setImageUrl(String imageUrl) {
123
+        this.imageUrl = imageUrl;
124
+    }
125
+
126
+    public boolean isActivated() {
127
+        return activated;
128
+    }
129
+
130
+    public void setActivated(boolean activated) {
131
+        this.activated = activated;
132
+    }
133
+
134
+    public String getLangKey() {
135
+        return langKey;
136
+    }
137
+
138
+    public void setLangKey(String langKey) {
139
+        this.langKey = langKey;
140
+    }
141
+
142
+    public String getCreatedBy() {
143
+        return createdBy;
144
+    }
145
+
146
+    public void setCreatedBy(String createdBy) {
147
+        this.createdBy = createdBy;
148
+    }
149
+
150
+    public Instant getCreatedDate() {
151
+        return createdDate;
152
+    }
153
+
154
+    public void setCreatedDate(Instant createdDate) {
155
+        this.createdDate = createdDate;
156
+    }
157
+
158
+    public String getLastModifiedBy() {
159
+        return lastModifiedBy;
160
+    }
161
+
162
+    public void setLastModifiedBy(String lastModifiedBy) {
163
+        this.lastModifiedBy = lastModifiedBy;
164
+    }
165
+
166
+    public Instant getLastModifiedDate() {
167
+        return lastModifiedDate;
168
+    }
169
+
170
+    public void setLastModifiedDate(Instant lastModifiedDate) {
171
+        this.lastModifiedDate = lastModifiedDate;
172
+    }
173
+
174
+    public Set<String> getAuthorities() {
175
+        return authorities;
176
+    }
177
+
178
+    public void setAuthorities(Set<String> authorities) {
179
+        this.authorities = authorities;
180
+    }
181
+
182
+    @Override
183
+    public String toString() {
184
+        return "UserDTO{" +
185
+            "login='" + login + '\'' +
186
+            ", firstName='" + firstName + '\'' +
187
+            ", lastName='" + lastName + '\'' +
188
+            ", email='" + email + '\'' +
189
+            ", imageUrl='" + imageUrl + '\'' +
190
+            ", activated=" + activated +
191
+            ", langKey='" + langKey + '\'' +
192
+            ", createdBy=" + createdBy +
193
+            ", createdDate=" + createdDate +
194
+            ", lastModifiedBy='" + lastModifiedBy + '\'' +
195
+            ", lastModifiedDate=" + lastModifiedDate +
196
+            ", authorities=" + authorities +
197
+            "}";
198
+    }
199
+}

+ 4
- 0
src/main/java/io/github/jhipster/application/service/dto/package-info.java 查看文件

@@ -0,0 +1,4 @@
1
+/**
2
+ * Data Transfer Objects.
3
+ */
4
+package io.github.jhipster.application.service.dto;

+ 76
- 0
src/main/java/io/github/jhipster/application/service/mapper/UserMapper.java 查看文件

@@ -0,0 +1,76 @@
1
+package io.github.jhipster.application.service.mapper;
2
+
3
+import io.github.jhipster.application.domain.Authority;
4
+import io.github.jhipster.application.domain.User;
5
+import io.github.jhipster.application.service.dto.UserDTO;
6
+
7
+import org.springframework.stereotype.Service;
8
+
9
+import java.util.*;
10
+import java.util.stream.Collectors;
11
+
12
+/**
13
+ * Mapper for the entity User and its DTO called UserDTO.
14
+ *
15
+ * Normal mappers are generated using MapStruct, this one is hand-coded as MapStruct
16
+ * support is still in beta, and requires a manual step with an IDE.
17
+ */
18
+@Service
19
+public class UserMapper {
20
+
21
+    public UserDTO userToUserDTO(User user) {
22
+        return new UserDTO(user);
23
+    }
24
+
25
+    public List<UserDTO> usersToUserDTOs(List<User> users) {
26
+        return users.stream()
27
+            .filter(Objects::nonNull)
28
+            .map(this::userToUserDTO)
29
+            .collect(Collectors.toList());
30
+    }
31
+
32
+    public User userDTOToUser(UserDTO userDTO) {
33
+        if (userDTO == null) {
34
+            return null;
35
+        } else {
36
+            User user = new User();
37
+            user.setId(userDTO.getId());
38
+            user.setLogin(userDTO.getLogin());
39
+            user.setFirstName(userDTO.getFirstName());
40
+            user.setLastName(userDTO.getLastName());
41
+            user.setEmail(userDTO.getEmail());
42
+            user.setImageUrl(userDTO.getImageUrl());
43
+            user.setActivated(userDTO.isActivated());
44
+            user.setLangKey(userDTO.getLangKey());
45
+            Set<Authority> authorities = this.authoritiesFromStrings(userDTO.getAuthorities());
46
+            if (authorities != null) {
47
+                user.setAuthorities(authorities);
48
+            }
49
+            return user;
50
+        }
51
+    }
52
+
53
+    public List<User> userDTOsToUsers(List<UserDTO> userDTOs) {
54
+        return userDTOs.stream()
55
+            .filter(Objects::nonNull)
56
+            .map(this::userDTOToUser)
57
+            .collect(Collectors.toList());
58
+    }
59
+
60
+    public User userFromId(Long id) {
61
+        if (id == null) {
62
+            return null;
63
+        }
64
+        User user = new User();
65
+        user.setId(id);
66
+        return user;
67
+    }
68
+
69
+    public Set<Authority> authoritiesFromStrings(Set<String> strings) {
70
+        return strings.stream().map(string -> {
71
+            Authority auth = new Authority();
72
+            auth.setName(string);
73
+            return auth;
74
+        }).collect(Collectors.toSet());
75
+    }
76
+}

+ 4
- 0
src/main/java/io/github/jhipster/application/service/mapper/package-info.java 查看文件

@@ -0,0 +1,4 @@
1
+/**
2
+ * MapStruct mappers for mapping domain objects and Data Transfer Objects.
3
+ */
4
+package io.github.jhipster.application.service.mapper;

+ 4
- 0
src/main/java/io/github/jhipster/application/service/package-info.java 查看文件

@@ -0,0 +1,4 @@
1
+/**
2
+ * Service layer beans.
3
+ */
4
+package io.github.jhipster.application.service;

+ 41
- 0
src/main/java/io/github/jhipster/application/service/util/RandomUtil.java 查看文件

@@ -0,0 +1,41 @@
1
+package io.github.jhipster.application.service.util;
2
+
3
+import org.apache.commons.lang3.RandomStringUtils;
4
+
5
+/**
6
+ * Utility class for generating random Strings.
7
+ */
8
+public final class RandomUtil {
9
+
10
+    private static final int DEF_COUNT = 20;
11
+
12
+    private RandomUtil() {
13
+    }
14
+
15
+    /**
16
+     * Generate a password.
17
+     *
18
+     * @return the generated password
19
+     */
20
+    public static String generatePassword() {
21
+        return RandomStringUtils.randomAlphanumeric(DEF_COUNT);
22
+    }
23
+
24
+    /**
25
+     * Generate an activation key.
26
+     *
27
+     * @return the generated activation key
28
+     */
29
+    public static String generateActivationKey() {
30
+        return RandomStringUtils.randomNumeric(DEF_COUNT);
31
+    }
32
+
33
+    /**
34
+     * Generate a reset key.
35
+     *
36
+     * @return the generated reset key
37
+     */
38
+    public static String generateResetKey() {
39
+        return RandomStringUtils.randomNumeric(DEF_COUNT);
40
+    }
41
+}

+ 189
- 0
src/main/java/io/github/jhipster/application/web/rest/AccountResource.java 查看文件

@@ -0,0 +1,189 @@
1
+package io.github.jhipster.application.web.rest;
2
+
3
+import com.codahale.metrics.annotation.Timed;
4
+
5
+import io.github.jhipster.application.domain.User;
6
+import io.github.jhipster.application.repository.UserRepository;
7
+import io.github.jhipster.application.security.SecurityUtils;
8
+import io.github.jhipster.application.service.MailService;
9
+import io.github.jhipster.application.service.UserService;
10
+import io.github.jhipster.application.service.dto.PasswordChangeDTO;
11
+import io.github.jhipster.application.service.dto.UserDTO;
12
+import io.github.jhipster.application.web.rest.errors.*;
13
+import io.github.jhipster.application.web.rest.vm.KeyAndPasswordVM;
14
+import io.github.jhipster.application.web.rest.vm.ManagedUserVM;
15
+
16
+import org.apache.commons.lang3.StringUtils;
17
+import org.slf4j.Logger;
18
+import org.slf4j.LoggerFactory;
19
+import org.springframework.http.HttpStatus;
20
+import org.springframework.web.bind.annotation.*;
21
+
22
+import javax.servlet.http.HttpServletRequest;
23
+import javax.validation.Valid;
24
+import java.util.*;
25
+
26
+
27
+/**
28
+ * REST controller for managing the current user's account.
29
+ */
30
+@RestController
31
+@RequestMapping("/api")
32
+public class AccountResource {
33
+
34
+    private final Logger log = LoggerFactory.getLogger(AccountResource.class);
35
+
36
+    private final UserRepository userRepository;
37
+
38
+    private final UserService userService;
39
+
40
+    private final MailService mailService;
41
+
42
+    public AccountResource(UserRepository userRepository, UserService userService, MailService mailService) {
43
+
44
+        this.userRepository = userRepository;
45
+        this.userService = userService;
46
+        this.mailService = mailService;
47
+    }
48
+
49
+    /**
50
+     * POST  /register : register the user.
51
+     *
52
+     * @param managedUserVM the managed user View Model
53
+     * @throws InvalidPasswordException 400 (Bad Request) if the password is incorrect
54
+     * @throws EmailAlreadyUsedException 400 (Bad Request) if the email is already used
55
+     * @throws LoginAlreadyUsedException 400 (Bad Request) if the login is already used
56
+     */
57
+    @PostMapping("/register")
58
+    @Timed
59
+    @ResponseStatus(HttpStatus.CREATED)
60
+    public void registerAccount(@Valid @RequestBody ManagedUserVM managedUserVM) {
61
+        if (!checkPasswordLength(managedUserVM.getPassword())) {
62
+            throw new InvalidPasswordException();
63
+        }
64
+        User user = userService.registerUser(managedUserVM, managedUserVM.getPassword());
65
+        mailService.sendActivationEmail(user);
66
+    }
67
+
68
+    /**
69
+     * GET  /activate : activate the registered user.
70
+     *
71
+     * @param key the activation key
72
+     * @throws RuntimeException 500 (Internal Server Error) if the user couldn't be activated
73
+     */
74
+    @GetMapping("/activate")
75
+    @Timed
76
+    public void activateAccount(@RequestParam(value = "key") String key) {
77
+        Optional<User> user = userService.activateRegistration(key);
78
+        if (!user.isPresent()) {
79
+            throw new InternalServerErrorException("No user was found for this activation key");
80
+        }
81
+    }
82
+
83
+    /**
84
+     * GET  /authenticate : check if the user is authenticated, and return its login.
85
+     *
86
+     * @param request the HTTP request
87
+     * @return the login if the user is authenticated
88
+     */
89
+    @GetMapping("/authenticate")
90
+    @Timed
91
+    public String isAuthenticated(HttpServletRequest request) {
92
+        log.debug("REST request to check if the current user is authenticated");
93
+        return request.getRemoteUser();
94
+    }
95
+
96
+    /**
97
+     * GET  /account : get the current user.
98
+     *
99
+     * @return the current user
100
+     * @throws RuntimeException 500 (Internal Server Error) if the user couldn't be returned
101
+     */
102
+    @GetMapping("/account")
103
+    @Timed
104
+    public UserDTO getAccount() {
105
+        return userService.getUserWithAuthorities()
106
+            .map(UserDTO::new)
107
+            .orElseThrow(() -> new InternalServerErrorException("User could not be found"));
108
+    }
109
+
110
+    /**
111
+     * POST  /account : update the current user information.
112
+     *
113
+     * @param userDTO the current user information
114
+     * @throws EmailAlreadyUsedException 400 (Bad Request) if the email is already used
115
+     * @throws RuntimeException 500 (Internal Server Error) if the user login wasn't found
116
+     */
117
+    @PostMapping("/account")
118
+    @Timed
119
+    public void saveAccount(@Valid @RequestBody UserDTO userDTO) {
120
+        final String userLogin = SecurityUtils.getCurrentUserLogin().orElseThrow(() -> new InternalServerErrorException("Current user login not found"));
121
+        Optional<User> existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail());
122
+        if (existingUser.isPresent() && (!existingUser.get().getLogin().equalsIgnoreCase(userLogin))) {
123
+            throw new EmailAlreadyUsedException();
124
+        }
125
+        Optional<User> user = userRepository.findOneByLogin(userLogin);
126
+        if (!user.isPresent()) {
127
+            throw new InternalServerErrorException("User could not be found");
128
+        }
129
+        userService.updateUser(userDTO.getFirstName(), userDTO.getLastName(), userDTO.getEmail(),
130
+            userDTO.getLangKey(), userDTO.getImageUrl());
131
+    }
132
+
133
+    /**
134
+     * POST  /account/change-password : changes the current user's password
135
+     *
136
+     * @param passwordChangeDto current and new password
137
+     * @throws InvalidPasswordException 400 (Bad Request) if the new password is incorrect
138
+     */
139
+    @PostMapping(path = "/account/change-password")
140
+    @Timed
141
+    public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) {
142
+        if (!checkPasswordLength(passwordChangeDto.getNewPassword())) {
143
+            throw new InvalidPasswordException();
144
+        }
145
+        userService.changePassword(passwordChangeDto.getCurrentPassword(), passwordChangeDto.getNewPassword());
146
+    }
147
+
148
+    /**
149
+     * POST   /account/reset-password/init : Send an email to reset the password of the user
150
+     *
151
+     * @param mail the mail of the user
152
+     * @throws EmailNotFoundException 400 (Bad Request) if the email address is not registered
153
+     */
154
+    @PostMapping(path = "/account/reset-password/init")
155
+    @Timed
156
+    public void requestPasswordReset(@RequestBody String mail) {
157
+       mailService.sendPasswordResetMail(
158
+           userService.requestPasswordReset(mail)
159
+               .orElseThrow(EmailNotFoundException::new)
160
+       );
161
+    }
162
+
163
+    /**
164
+     * POST   /account/reset-password/finish : Finish to reset the password of the user
165
+     *
166
+     * @param keyAndPassword the generated key and the new password
167
+     * @throws InvalidPasswordException 400 (Bad Request) if the password is incorrect
168
+     * @throws RuntimeException 500 (Internal Server Error) if the password could not be reset
169
+     */
170
+    @PostMapping(path = "/account/reset-password/finish")
171
+    @Timed
172
+    public void finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) {
173
+        if (!checkPasswordLength(keyAndPassword.getNewPassword())) {
174
+            throw new InvalidPasswordException();
175
+        }
176
+        Optional<User> user =
177
+            userService.completePasswordReset(keyAndPassword.getNewPassword(), keyAndPassword.getKey());
178
+
179
+        if (!user.isPresent()) {
180
+            throw new InternalServerErrorException("No user was found for this reset key");
181
+        }
182
+    }
183
+
184
+    private static boolean checkPasswordLength(String password) {
185
+        return !StringUtils.isEmpty(password) &&
186
+            password.length() >= ManagedUserVM.PASSWORD_MIN_LENGTH &&
187
+            password.length() <= ManagedUserVM.PASSWORD_MAX_LENGTH;
188
+    }
189
+}

+ 77
- 0
src/main/java/io/github/jhipster/application/web/rest/AuditResource.java 查看文件

@@ -0,0 +1,77 @@
1
+package io.github.jhipster.application.web.rest;
2
+
3
+import io.github.jhipster.application.service.AuditEventService;
4
+import io.github.jhipster.application.web.rest.util.PaginationUtil;
5
+
6
+import io.github.jhipster.web.util.ResponseUtil;
7
+import org.springframework.boot.actuate.audit.AuditEvent;
8
+import org.springframework.data.domain.Page;
9
+import org.springframework.data.domain.Pageable;
10
+import org.springframework.http.HttpHeaders;
11
+import org.springframework.http.HttpStatus;
12
+import org.springframework.http.ResponseEntity;
13
+import org.springframework.web.bind.annotation.*;
14
+
15
+import java.time.LocalDate;
16
+import java.time.ZoneId;
17
+import java.util.List;
18
+
19
+/**
20
+ * REST controller for getting the audit events.
21
+ */
22
+@RestController
23
+@RequestMapping("/management/audits")
24
+public class AuditResource {
25
+
26
+    private final AuditEventService auditEventService;
27
+
28
+    public AuditResource(AuditEventService auditEventService) {
29
+        this.auditEventService = auditEventService;
30
+    }
31
+
32
+    /**
33
+     * GET /audits : get a page of AuditEvents.
34
+     *
35
+     * @param pageable the pagination information
36
+     * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body
37
+     */
38
+    @GetMapping
39
+    public ResponseEntity<List<AuditEvent>> getAll(Pageable pageable) {
40
+        Page<AuditEvent> page = auditEventService.findAll(pageable);
41
+        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits");
42
+        return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
43
+    }
44
+
45
+    /**
46
+     * GET  /audits : get a page of AuditEvents between the fromDate and toDate.
47
+     *
48
+     * @param fromDate the start of the time period of AuditEvents to get
49
+     * @param toDate the end of the time period of AuditEvents to get
50
+     * @param pageable the pagination information
51
+     * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body
52
+     */
53
+    @GetMapping(params = {"fromDate", "toDate"})
54
+    public ResponseEntity<List<AuditEvent>> getByDates(
55
+        @RequestParam(value = "fromDate") LocalDate fromDate,
56
+        @RequestParam(value = "toDate") LocalDate toDate,
57
+        Pageable pageable) {
58
+
59
+        Page<AuditEvent> page = auditEventService.findByDates(
60
+            fromDate.atStartOfDay(ZoneId.systemDefault()).toInstant(),
61
+            toDate.atStartOfDay(ZoneId.systemDefault()).plusDays(1).toInstant(),
62
+            pageable);
63
+        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits");
64
+        return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
65
+    }
66
+
67
+    /**
68
+     * GET  /audits/:id : get an AuditEvent by id.
69
+     *
70
+     * @param id the id of the entity to get
71
+     * @return the ResponseEntity with status 200 (OK) and the AuditEvent in body, or status 404 (Not Found)
72
+     */
73
+    @GetMapping("/{id:.+}")
74
+    public ResponseEntity<AuditEvent> get(@PathVariable Long id) {
75
+        return ResponseUtil.wrapOrNotFound(auditEventService.find(id));
76
+    }
77
+}

+ 39
- 0
src/main/java/io/github/jhipster/application/web/rest/LogsResource.java 查看文件

@@ -0,0 +1,39 @@
1
+package io.github.jhipster.application.web.rest;
2
+
3
+import io.github.jhipster.application.web.rest.vm.LoggerVM;
4
+
5
+import ch.qos.logback.classic.Level;
6
+import ch.qos.logback.classic.LoggerContext;
7
+import com.codahale.metrics.annotation.Timed;
8
+import org.slf4j.LoggerFactory;
9
+import org.springframework.http.HttpStatus;
10
+import org.springframework.web.bind.annotation.*;
11
+
12
+import java.util.List;
13
+import java.util.stream.Collectors;
14
+
15
+/**
16
+ * Controller for view and managing Log Level at runtime.
17
+ */
18
+@RestController
19
+@RequestMapping("/management")
20
+public class LogsResource {
21
+
22
+    @GetMapping("/logs")
23
+    @Timed
24
+    public List<LoggerVM> getList() {
25
+        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
26
+        return context.getLoggerList()
27
+            .stream()
28
+            .map(LoggerVM::new)
29
+            .collect(Collectors.toList());
30
+    }
31
+
32
+    @PutMapping("/logs")
33
+    @ResponseStatus(HttpStatus.NO_CONTENT)
34
+    @Timed
35
+    public void changeLevel(@RequestBody LoggerVM jsonLogger) {
36
+        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
37
+        context.getLogger(jsonLogger.getName()).setLevel(Level.valueOf(jsonLogger.getLevel()));
38
+    }
39
+}

+ 73
- 0
src/main/java/io/github/jhipster/application/web/rest/UserJWTController.java 查看文件

@@ -0,0 +1,73 @@
1
+package io.github.jhipster.application.web.rest;
2
+
3
+import io.github.jhipster.application.security.jwt.JWTFilter;
4
+import io.github.jhipster.application.security.jwt.TokenProvider;
5
+import io.github.jhipster.application.web.rest.vm.LoginVM;
6
+
7
+import com.codahale.metrics.annotation.Timed;
8
+import com.fasterxml.jackson.annotation.JsonProperty;
9
+
10
+import org.springframework.http.HttpHeaders;
11
+import org.springframework.http.HttpStatus;
12
+import org.springframework.http.ResponseEntity;
13
+import org.springframework.security.authentication.AuthenticationManager;
14
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
15
+import org.springframework.security.core.Authentication;
16
+import org.springframework.security.core.context.SecurityContextHolder;
17
+import org.springframework.web.bind.annotation.*;
18
+
19
+import javax.validation.Valid;
20
+
21
+/**
22
+ * Controller to authenticate users.
23
+ */
24
+@RestController
25
+@RequestMapping("/api")
26
+public class UserJWTController {
27
+
28
+    private final TokenProvider tokenProvider;
29
+
30
+    private final AuthenticationManager authenticationManager;
31
+
32
+    public UserJWTController(TokenProvider tokenProvider, AuthenticationManager authenticationManager) {
33
+        this.tokenProvider = tokenProvider;
34
+        this.authenticationManager = authenticationManager;
35
+    }
36
+
37
+    @PostMapping("/authenticate")
38
+    @Timed
39
+    public ResponseEntity<JWTToken> authorize(@Valid @RequestBody LoginVM loginVM) {
40
+
41
+        UsernamePasswordAuthenticationToken authenticationToken =
42
+            new UsernamePasswordAuthenticationToken(loginVM.getUsername(), loginVM.getPassword());
43
+
44
+        Authentication authentication = this.authenticationManager.authenticate(authenticationToken);
45
+        SecurityContextHolder.getContext().setAuthentication(authentication);
46
+        boolean rememberMe = (loginVM.isRememberMe() == null) ? false : loginVM.isRememberMe();
47
+        String jwt = tokenProvider.createToken(authentication, rememberMe);
48
+        HttpHeaders httpHeaders = new HttpHeaders();
49
+        httpHeaders.add(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt);
50
+        return new ResponseEntity<>(new JWTToken(jwt), httpHeaders, HttpStatus.OK);
51
+    }
52
+
53
+    /**
54
+     * Object to return as body in JWT Authentication.
55
+     */
56
+    static class JWTToken {
57
+
58
+        private String idToken;
59
+
60
+        JWTToken(String idToken) {
61
+            this.idToken = idToken;
62
+        }
63
+
64
+        @JsonProperty("id_token")
65
+        String getIdToken() {
66
+            return idToken;
67
+        }
68
+
69
+        void setIdToken(String idToken) {
70
+            this.idToken = idToken;
71
+        }
72
+    }
73
+}

+ 213
- 0
src/main/java/io/github/jhipster/application/web/rest/UserResource.java 查看文件

@@ -0,0 +1,213 @@
1
+package io.github.jhipster.application.web.rest;
2
+
3
+import io.github.jhipster.application.config.Constants;
4
+import io.github.jhipster.application.domain.User;
5
+import io.github.jhipster.application.repository.UserRepository;
6
+import io.github.jhipster.application.repository.search.UserSearchRepository;
7
+import io.github.jhipster.application.security.AuthoritiesConstants;
8
+import io.github.jhipster.application.service.MailService;
9
+import io.github.jhipster.application.service.UserService;
10
+import io.github.jhipster.application.service.dto.UserDTO;
11
+import io.github.jhipster.application.web.rest.errors.BadRequestAlertException;
12
+import io.github.jhipster.application.web.rest.errors.EmailAlreadyUsedException;
13
+import io.github.jhipster.application.web.rest.errors.LoginAlreadyUsedException;
14
+import io.github.jhipster.application.web.rest.util.HeaderUtil;
15
+import io.github.jhipster.application.web.rest.util.PaginationUtil;
16
+import com.codahale.metrics.annotation.Timed;
17
+import io.github.jhipster.web.util.ResponseUtil;
18
+
19
+import org.slf4j.Logger;
20
+import org.slf4j.LoggerFactory;
21
+import org.springframework.data.domain.Page;
22
+import org.springframework.data.domain.Pageable;
23
+import org.springframework.http.HttpHeaders;
24
+import org.springframework.http.HttpStatus;
25
+import org.springframework.http.ResponseEntity;
26
+import org.springframework.security.access.prepost.PreAuthorize;
27
+import org.springframework.web.bind.annotation.*;
28
+
29
+import javax.validation.Valid;
30
+import java.net.URI;
31
+import java.net.URISyntaxException;
32
+import java.util.*;
33
+import java.util.stream.Collectors;
34
+import java.util.stream.StreamSupport;
35
+
36
+import static org.elasticsearch.index.query.QueryBuilders.*;
37
+
38
+/**
39
+ * REST controller for managing users.
40
+ * <p>
41
+ * This class accesses the User entity, and needs to fetch its collection of authorities.
42
+ * <p>
43
+ * For a normal use-case, it would be better to have an eager relationship between User and Authority,
44
+ * and send everything to the client side: there would be no View Model and DTO, a lot less code, and an outer-join
45
+ * which would be good for performance.
46
+ * <p>
47
+ * We use a View Model and a DTO for 3 reasons:
48
+ * <ul>
49
+ * <li>We want to keep a lazy association between the user and the authorities, because people will
50
+ * quite often do relationships with the user, and we don't want them to get the authorities all
51
+ * the time for nothing (for performance reasons). This is the #1 goal: we should not impact our users'
52
+ * application because of this use-case.</li>
53
+ * <li> Not having an outer join causes n+1 requests to the database. This is not a real issue as
54
+ * we have by default a second-level cache. This means on the first HTTP call we do the n+1 requests,
55
+ * but then all authorities come from the cache, so in fact it's much better than doing an outer join
56
+ * (which will get lots of data from the database, for each HTTP call).</li>
57
+ * <li> As this manages users, for security reasons, we'd rather have a DTO layer.</li>
58
+ * </ul>
59
+ * <p>
60
+ * Another option would be to have a specific JPA entity graph to handle this case.
61
+ */
62
+@RestController
63
+@RequestMapping("/api")
64
+public class UserResource {
65
+
66
+    private final Logger log = LoggerFactory.getLogger(UserResource.class);
67
+
68
+    private final UserService userService;
69
+
70
+    private final UserRepository userRepository;
71
+
72
+    private final MailService mailService;
73
+
74
+    private final UserSearchRepository userSearchRepository;
75
+
76
+    public UserResource(UserService userService, UserRepository userRepository, MailService mailService, UserSearchRepository userSearchRepository) {
77
+
78
+        this.userService = userService;
79
+        this.userRepository = userRepository;
80
+        this.mailService = mailService;
81
+        this.userSearchRepository = userSearchRepository;
82
+    }
83
+
84
+    /**
85
+     * POST  /users  : Creates a new user.
86
+     * <p>
87
+     * Creates a new user if the login and email are not already used, and sends an
88
+     * mail with an activation link.
89
+     * The user needs to be activated on creation.
90
+     *
91
+     * @param userDTO the user to create
92
+     * @return the ResponseEntity with status 201 (Created) and with body the new user, or with status 400 (Bad Request) if the login or email is already in use
93
+     * @throws URISyntaxException if the Location URI syntax is incorrect
94
+     * @throws BadRequestAlertException 400 (Bad Request) if the login or email is already in use
95
+     */
96
+    @PostMapping("/users")
97
+    @Timed
98
+    @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")")
99
+    public ResponseEntity<User> createUser(@Valid @RequestBody UserDTO userDTO) throws URISyntaxException {
100
+        log.debug("REST request to save User : {}", userDTO);
101
+
102
+        if (userDTO.getId() != null) {
103
+            throw new BadRequestAlertException("A new user cannot already have an ID", "userManagement", "idexists");
104
+            // Lowercase the user login before comparing with database
105
+        } else if (userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()).isPresent()) {
106
+            throw new LoginAlreadyUsedException();
107
+        } else if (userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()).isPresent()) {
108
+            throw new EmailAlreadyUsedException();
109
+        } else {
110
+            User newUser = userService.createUser(userDTO);
111
+            mailService.sendCreationEmail(newUser);
112
+            return ResponseEntity.created(new URI("/api/users/" + newUser.getLogin()))
113
+                .headers(HeaderUtil.createAlert( "A user is created with identifier " + newUser.getLogin(), newUser.getLogin()))
114
+                .body(newUser);
115
+        }
116
+    }
117
+
118
+    /**
119
+     * PUT /users : Updates an existing User.
120
+     *
121
+     * @param userDTO the user to update
122
+     * @return the ResponseEntity with status 200 (OK) and with body the updated user
123
+     * @throws EmailAlreadyUsedException 400 (Bad Request) if the email is already in use
124
+     * @throws LoginAlreadyUsedException 400 (Bad Request) if the login is already in use
125
+     */
126
+    @PutMapping("/users")
127
+    @Timed
128
+    @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")")
129
+    public ResponseEntity<UserDTO> updateUser(@Valid @RequestBody UserDTO userDTO) {
130
+        log.debug("REST request to update User : {}", userDTO);
131
+        Optional<User> existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail());
132
+        if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) {
133
+            throw new EmailAlreadyUsedException();
134
+        }
135
+        existingUser = userRepository.findOneByLogin(userDTO.getLogin().toLowerCase());
136
+        if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) {
137
+            throw new LoginAlreadyUsedException();
138
+        }
139
+        Optional<UserDTO> updatedUser = userService.updateUser(userDTO);
140
+
141
+        return ResponseUtil.wrapOrNotFound(updatedUser,
142
+            HeaderUtil.createAlert("A user is updated with identifier " + userDTO.getLogin(), userDTO.getLogin()));
143
+    }
144
+
145
+    /**
146
+     * GET /users : get all users.
147
+     *
148
+     * @param pageable the pagination information
149
+     * @return the ResponseEntity with status 200 (OK) and with body all users
150
+     */
151
+    @GetMapping("/users")
152
+    @Timed
153
+    public ResponseEntity<List<UserDTO>> getAllUsers(Pageable pageable) {
154
+        final Page<UserDTO> page = userService.getAllManagedUsers(pageable);
155
+        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/users");
156
+        return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
157
+    }
158
+
159
+    /**
160
+     * @return a string list of the all of the roles
161
+     */
162
+    @GetMapping("/users/authorities")
163
+    @Timed
164
+    @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")")
165
+    public List<String> getAuthorities() {
166
+        return userService.getAuthorities();
167
+    }
168
+
169
+    /**
170
+     * GET /users/:login : get the "login" user.
171
+     *
172
+     * @param login the login of the user to find
173
+     * @return the ResponseEntity with status 200 (OK) and with body the "login" user, or with status 404 (Not Found)
174
+     */
175
+    @GetMapping("/users/{login:" + Constants.LOGIN_REGEX + "}")
176
+    @Timed
177
+    public ResponseEntity<UserDTO> getUser(@PathVariable String login) {
178
+        log.debug("REST request to get User : {}", login);
179
+        return ResponseUtil.wrapOrNotFound(
180
+            userService.getUserWithAuthoritiesByLogin(login)
181
+                .map(UserDTO::new));
182
+    }
183
+
184
+    /**
185
+     * DELETE /users/:login : delete the "login" User.
186
+     *
187
+     * @param login the login of the user to delete
188
+     * @return the ResponseEntity with status 200 (OK)
189
+     */
190
+    @DeleteMapping("/users/{login:" + Constants.LOGIN_REGEX + "}")
191
+    @Timed
192
+    @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")")
193
+    public ResponseEntity<Void> deleteUser(@PathVariable String login) {
194
+        log.debug("REST request to delete User: {}", login);
195
+        userService.deleteUser(login);
196
+        return ResponseEntity.ok().headers(HeaderUtil.createAlert( "A user is deleted with identifier " + login, login)).build();
197
+    }
198
+
199
+    /**
200
+     * SEARCH /_search/users/:query : search for the User corresponding
201
+     * to the query.
202
+     *
203
+     * @param query the query to search
204
+     * @return the result of the search
205
+     */
206
+    @GetMapping("/_search/users/{query}")
207
+    @Timed
208
+    public List<User> search(@PathVariable String query) {
209
+        return StreamSupport
210
+            .stream(userSearchRepository.search(queryStringQuery(query)).spliterator(), false)
211
+            .collect(Collectors.toList());
212
+    }
213
+}

+ 42
- 0
src/main/java/io/github/jhipster/application/web/rest/errors/BadRequestAlertException.java 查看文件

@@ -0,0 +1,42 @@
1
+package io.github.jhipster.application.web.rest.errors;
2
+
3
+import org.zalando.problem.AbstractThrowableProblem;
4
+import org.zalando.problem.Status;
5
+
6
+import java.net.URI;
7
+import java.util.HashMap;
8
+import java.util.Map;
9
+
10
+public class BadRequestAlertException extends AbstractThrowableProblem {
11
+
12
+    private static final long serialVersionUID = 1L;
13
+
14
+    private final String entityName;
15
+
16
+    private final String errorKey;
17
+
18
+    public BadRequestAlertException(String defaultMessage, String entityName, String errorKey) {
19
+        this(ErrorConstants.DEFAULT_TYPE, defaultMessage, entityName, errorKey);
20
+    }
21
+
22
+    public BadRequestAlertException(URI type, String defaultMessage, String entityName, String errorKey) {
23
+        super(type, defaultMessage, Status.BAD_REQUEST, null, null, null, getAlertParameters(entityName, errorKey));
24
+        this.entityName = entityName;
25
+        this.errorKey = errorKey;
26
+    }
27
+
28
+    public String getEntityName() {
29
+        return entityName;
30
+    }
31
+
32
+    public String getErrorKey() {
33
+        return errorKey;
34
+    }
35
+
36
+    private static Map<String, Object> getAlertParameters(String entityName, String errorKey) {
37
+        Map<String, Object> parameters = new HashMap<>();
38
+        parameters.put("message", "error." + errorKey);
39
+        parameters.put("params", entityName);
40
+        return parameters;
41
+    }
42
+}

+ 54
- 0
src/main/java/io/github/jhipster/application/web/rest/errors/CustomParameterizedException.java 查看文件

@@ -0,0 +1,54 @@
1
+package io.github.jhipster.application.web.rest.errors;
2
+
3
+import org.zalando.problem.AbstractThrowableProblem;
4
+
5
+import java.util.HashMap;
6
+import java.util.Map;
7
+
8
+import static org.zalando.problem.Status.BAD_REQUEST;
9
+
10
+/**
11
+ * Custom, parameterized exception, which can be translated on the client side.
12
+ * For example:
13
+ *
14
+ * <pre>
15
+ * throw new CustomParameterizedException(&quot;myCustomError&quot;, &quot;hello&quot;, &quot;world&quot;);
16
+ * </pre>
17
+ *
18
+ * Can be translated with:
19
+ *
20
+ * <pre>
21
+ * "error.myCustomError" :  "The server says {{param0}} to {{param1}}"
22
+ * </pre>
23
+ */
24
+public class CustomParameterizedException extends AbstractThrowableProblem {
25
+
26
+    private static final long serialVersionUID = 1L;
27
+
28
+    private static final String PARAM = "param";
29
+
30
+    public CustomParameterizedException(String message, String... params) {
31
+        this(message, toParamMap(params));
32
+    }
33
+
34
+    public CustomParameterizedException(String message, Map<String, Object> paramMap) {
35
+        super(ErrorConstants.PARAMETERIZED_TYPE, "Parameterized Exception", BAD_REQUEST, null, null, null, toProblemParameters(message, paramMap));
36
+    }
37
+
38
+    public static Map<String, Object> toParamMap(String... params) {
39
+        Map<String, Object> paramMap = new HashMap<>();
40
+        if (params != null && params.length > 0) {
41
+            for (int i = 0; i < params.length; i++) {
42
+                paramMap.put(PARAM + i, params[i]);
43
+            }
44
+        }
45
+        return paramMap;
46
+    }
47
+
48
+    public static Map<String, Object> toProblemParameters(String message, Map<String, Object> paramMap) {
49
+        Map<String, Object> parameters = new HashMap<>();
50
+        parameters.put("message", message);
51
+        parameters.put("params", paramMap);
52
+        return parameters;
53
+    }
54
+}

+ 10
- 0
src/main/java/io/github/jhipster/application/web/rest/errors/EmailAlreadyUsedException.java 查看文件

@@ -0,0 +1,10 @@
1
+package io.github.jhipster.application.web.rest.errors;
2
+
3
+public class EmailAlreadyUsedException extends BadRequestAlertException {
4
+
5
+    private static final long serialVersionUID = 1L;
6
+
7
+    public EmailAlreadyUsedException() {
8
+        super(ErrorConstants.EMAIL_ALREADY_USED_TYPE, "Email is already in use!", "userManagement", "emailexists");
9
+    }
10
+}

+ 13
- 0
src/main/java/io/github/jhipster/application/web/rest/errors/EmailNotFoundException.java 查看文件

@@ -0,0 +1,13 @@
1
+package io.github.jhipster.application.web.rest.errors;
2
+
3
+import org.zalando.problem.AbstractThrowableProblem;
4
+import org.zalando.problem.Status;
5
+
6
+public class EmailNotFoundException extends AbstractThrowableProblem {
7
+
8
+    private static final long serialVersionUID = 1L;
9
+
10
+    public EmailNotFoundException() {
11
+        super(ErrorConstants.EMAIL_NOT_FOUND_TYPE, "Email address not registered", Status.BAD_REQUEST);
12
+    }
13
+}

+ 21
- 0
src/main/java/io/github/jhipster/application/web/rest/errors/ErrorConstants.java 查看文件

@@ -0,0 +1,21 @@
1
+package io.github.jhipster.application.web.rest.errors;
2
+
3
+import java.net.URI;
4
+
5
+public final class ErrorConstants {
6
+
7
+    public static final String ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure";
8
+    public static final String ERR_VALIDATION = "error.validation";
9
+    public static final String PROBLEM_BASE_URL = "https://www.jhipster.tech/problem";
10
+    public static final URI DEFAULT_TYPE = URI.create(PROBLEM_BASE_URL + "/problem-with-message");
11
+    public static final URI CONSTRAINT_VIOLATION_TYPE = URI.create(PROBLEM_BASE_URL + "/constraint-violation");
12
+    public static final URI PARAMETERIZED_TYPE = URI.create(PROBLEM_BASE_URL + "/parameterized");
13
+    public static final URI ENTITY_NOT_FOUND_TYPE = URI.create(PROBLEM_BASE_URL + "/entity-not-found");
14
+    public static final URI INVALID_PASSWORD_TYPE = URI.create(PROBLEM_BASE_URL + "/invalid-password");
15
+    public static final URI EMAIL_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/email-already-used");
16
+    public static final URI LOGIN_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/login-already-used");
17
+    public static final URI EMAIL_NOT_FOUND_TYPE = URI.create(PROBLEM_BASE_URL + "/email-not-found");
18
+
19
+    private ErrorConstants() {
20
+    }
21
+}

+ 107
- 0
src/main/java/io/github/jhipster/application/web/rest/errors/ExceptionTranslator.java 查看文件

@@ -0,0 +1,107 @@
1
+package io.github.jhipster.application.web.rest.errors;
2
+
3
+import io.github.jhipster.application.web.rest.util.HeaderUtil;
4
+
5
+import org.springframework.dao.ConcurrencyFailureException;
6
+import org.springframework.http.ResponseEntity;
7
+import org.springframework.validation.BindingResult;
8
+import org.springframework.web.bind.MethodArgumentNotValidException;
9
+import org.springframework.web.bind.annotation.ControllerAdvice;
10
+import org.springframework.web.bind.annotation.ExceptionHandler;
11
+import org.springframework.web.context.request.NativeWebRequest;
12
+import org.zalando.problem.DefaultProblem;
13
+import org.zalando.problem.Problem;
14
+import org.zalando.problem.ProblemBuilder;
15
+import org.zalando.problem.Status;
16
+import org.zalando.problem.spring.web.advice.ProblemHandling;
17
+import org.zalando.problem.violations.ConstraintViolationProblem;
18
+
19
+import javax.annotation.Nonnull;
20
+import javax.annotation.Nullable;
21
+import javax.servlet.http.HttpServletRequest;
22
+import java.util.List;
23
+import java.util.NoSuchElementException;
24
+import java.util.stream.Collectors;
25
+
26
+/**
27
+ * Controller advice to translate the server side exceptions to client-friendly json structures.
28
+ * The error response follows RFC7807 - Problem Details for HTTP APIs (https://tools.ietf.org/html/rfc7807)
29
+ */
30
+@ControllerAdvice
31
+public class ExceptionTranslator implements ProblemHandling {
32
+
33
+    /**
34
+     * Post-process the Problem payload to add the message key for the front-end if needed
35
+     */
36
+    @Override
37
+    public ResponseEntity<Problem> process(@Nullable ResponseEntity<Problem> entity, NativeWebRequest request) {
38
+        if (entity == null) {
39
+            return entity;
40
+        }
41
+        Problem problem = entity.getBody();
42
+        if (!(problem instanceof ConstraintViolationProblem || problem instanceof DefaultProblem)) {
43
+            return entity;
44
+        }
45
+        ProblemBuilder builder = Problem.builder()
46
+            .withType(Problem.DEFAULT_TYPE.equals(problem.getType()) ? ErrorConstants.DEFAULT_TYPE : problem.getType())
47
+            .withStatus(problem.getStatus())
48
+            .withTitle(problem.getTitle())
49
+            .with("path", request.getNativeRequest(HttpServletRequest.class).getRequestURI());
50
+
51
+        if (problem instanceof ConstraintViolationProblem) {
52
+            builder
53
+                .with("violations", ((ConstraintViolationProblem) problem).getViolations())
54
+                .with("message", ErrorConstants.ERR_VALIDATION);
55
+        } else {
56
+            builder
57
+                .withCause(((DefaultProblem) problem).getCause())
58
+                .withDetail(problem.getDetail())
59
+                .withInstance(problem.getInstance());
60
+            problem.getParameters().forEach(builder::with);
61
+            if (!problem.getParameters().containsKey("message") && problem.getStatus() != null) {
62
+                builder.with("message", "error.http." + problem.getStatus().getStatusCode());
63
+            }
64
+        }
65
+        return new ResponseEntity<>(builder.build(), entity.getHeaders(), entity.getStatusCode());
66
+    }
67
+
68
+    @Override
69
+    public ResponseEntity<Problem> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, @Nonnull NativeWebRequest request) {
70
+        BindingResult result = ex.getBindingResult();
71
+        List<FieldErrorVM> fieldErrors = result.getFieldErrors().stream()
72
+            .map(f -> new FieldErrorVM(f.getObjectName(), f.getField(), f.getCode()))
73
+            .collect(Collectors.toList());
74
+
75
+        Problem problem = Problem.builder()
76
+            .withType(ErrorConstants.CONSTRAINT_VIOLATION_TYPE)
77
+            .withTitle("Method argument not valid")
78
+            .withStatus(defaultConstraintViolationStatus())
79
+            .with("message", ErrorConstants.ERR_VALIDATION)
80
+            .with("fieldErrors", fieldErrors)
81
+            .build();
82
+        return create(ex, problem, request);
83
+    }
84
+
85
+    @ExceptionHandler
86
+    public ResponseEntity<Problem> handleNoSuchElementException(NoSuchElementException ex, NativeWebRequest request) {
87
+        Problem problem = Problem.builder()
88
+            .withStatus(Status.NOT_FOUND)
89
+            .with("message", ErrorConstants.ENTITY_NOT_FOUND_TYPE)
90
+            .build();
91
+        return create(ex, problem, request);
92
+    }
93
+
94
+    @ExceptionHandler
95
+    public ResponseEntity<Problem> handleBadRequestAlertException(BadRequestAlertException ex, NativeWebRequest request) {
96
+        return create(ex, request, HeaderUtil.createFailureAlert(ex.getEntityName(), ex.getErrorKey(), ex.getMessage()));
97
+    }
98
+
99
+    @ExceptionHandler
100
+    public ResponseEntity<Problem> handleConcurrencyFailure(ConcurrencyFailureException ex, NativeWebRequest request) {
101
+        Problem problem = Problem.builder()
102
+            .withStatus(Status.CONFLICT)
103
+            .with("message", ErrorConstants.ERR_CONCURRENCY_FAILURE)
104
+            .build();
105
+        return create(ex, problem, request);
106
+    }
107
+}

+ 33
- 0
src/main/java/io/github/jhipster/application/web/rest/errors/FieldErrorVM.java 查看文件

@@ -0,0 +1,33 @@
1
+package io.github.jhipster.application.web.rest.errors;
2
+
3
+import java.io.Serializable;
4
+
5
+public class FieldErrorVM implements Serializable {
6
+
7
+    private static final long serialVersionUID = 1L;
8
+
9
+    private final String objectName;
10
+
11
+    private final String field;
12
+
13
+    private final String message;
14
+
15
+    public FieldErrorVM(String dto, String field, String message) {
16
+        this.objectName = dto;
17
+        this.field = field;
18
+        this.message = message;
19
+    }
20
+
21
+    public String getObjectName() {
22
+        return objectName;
23
+    }
24
+
25
+    public String getField() {
26
+        return field;
27
+    }
28
+
29
+    public String getMessage() {
30
+        return message;
31
+    }
32
+
33
+}

+ 16
- 0
src/main/java/io/github/jhipster/application/web/rest/errors/InternalServerErrorException.java 查看文件

@@ -0,0 +1,16 @@
1
+package io.github.jhipster.application.web.rest.errors;
2
+
3
+import org.zalando.problem.AbstractThrowableProblem;
4
+import org.zalando.problem.Status;
5
+
6
+/**
7
+ * Simple exception with a message, that returns an Internal Server Error code.
8
+ */
9
+public class InternalServerErrorException extends AbstractThrowableProblem {
10
+
11
+    private static final long serialVersionUID = 1L;
12
+
13
+    public InternalServerErrorException(String message) {
14
+        super(ErrorConstants.DEFAULT_TYPE, message, Status.INTERNAL_SERVER_ERROR);
15
+    }
16
+}

+ 13
- 0
src/main/java/io/github/jhipster/application/web/rest/errors/InvalidPasswordException.java 查看文件

@@ -0,0 +1,13 @@
1
+package io.github.jhipster.application.web.rest.errors;
2
+
3
+import org.zalando.problem.AbstractThrowableProblem;
4
+import org.zalando.problem.Status;
5
+
6
+public class InvalidPasswordException extends AbstractThrowableProblem {
7
+
8
+    private static final long serialVersionUID = 1L;
9
+
10
+    public InvalidPasswordException() {
11
+        super(ErrorConstants.INVALID_PASSWORD_TYPE, "Incorrect password", Status.BAD_REQUEST);
12
+    }
13
+}

+ 10
- 0
src/main/java/io/github/jhipster/application/web/rest/errors/LoginAlreadyUsedException.java 查看文件

@@ -0,0 +1,10 @@
1
+package io.github.jhipster.application.web.rest.errors;
2
+
3
+public class LoginAlreadyUsedException extends BadRequestAlertException {
4
+
5
+    private static final long serialVersionUID = 1L;
6
+
7
+    public LoginAlreadyUsedException() {
8
+        super(ErrorConstants.LOGIN_ALREADY_USED_TYPE, "Login name already used!", "userManagement", "userexists");
9
+    }
10
+}

+ 0
- 0
src/main/java/io/github/jhipster/application/web/rest/errors/package-info.java 查看文件


部分文件因文件數量過多而無法顯示