BAEL-137 Intro do JHipster (#1427)
* refactor: Reorder tests without lambda Moves inner implementations of Answer and ArgumentMatcher to the top of the test classes. Also changes the lambda expression to a regular "pre java 8" expression in one of the tests. Resolves: BAEL-632 * feat: Create basic Monolithic JHipster project Commit just after creating a JHipster project, before making any modifications. Resolves: BAEL-137 * chore: Change the artifactId and name of the project From baeldung to jhipster-monolithic and JHipster Monolithic Application Relates to: BAEL-137 * feat: Create entities Post and Comment Relates to: BAEL-137 * feat: Fix Gatling configuration in pom.xml Relates to: BAEL-137 * feat: Add files for Continuous Integration Relates to: BAEL-137 * feat: Change pom.xml to conform to Baeldung standards - moved the <properties> element to the bottom of the file - excluded integration tests in the default surefire configuration - added a new profile, called integration, and added the integration tests there - added Java 8 in the <source> and <target> tags, under maven-compiler solves: BAEL-137 * chore: Add jhipster module to parent pom
This commit is contained in:
parent
07c0e84bf4
commit
78f87104d6
|
@ -0,0 +1,24 @@
|
|||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
|
||||
# Change these settings to your own preference
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
# We recommend you to keep these unchanged
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[{package,bower}.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
|
@ -0,0 +1,22 @@
|
|||
# All text files should have the "lf" (Unix) line endings
|
||||
* text eol=lf
|
||||
|
||||
# Explicitly declare text files you want to always be normalized and converted
|
||||
# to native line endings on checkout.
|
||||
*.java text
|
||||
*.js text
|
||||
*.css text
|
||||
*.html text
|
||||
|
||||
# Denote all files that are truly binary and should not be modified.
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jar binary
|
||||
*.pdf binary
|
||||
*.eot binary
|
||||
*.ttf binary
|
||||
*.gzip binary
|
||||
*.gz binary
|
||||
*.ai binary
|
||||
*.eps binary
|
||||
*.swf binary
|
|
@ -0,0 +1,143 @@
|
|||
######################
|
||||
# Project Specific
|
||||
######################
|
||||
/src/main/webapp/content/css/main.css
|
||||
/target/www/**
|
||||
/src/test/javascript/coverage/
|
||||
/src/test/javascript/PhantomJS*/
|
||||
|
||||
######################
|
||||
# Node
|
||||
######################
|
||||
/node/
|
||||
node_tmp/
|
||||
node_modules/
|
||||
npm-debug.log.*
|
||||
|
||||
######################
|
||||
# SASS
|
||||
######################
|
||||
.sass-cache/
|
||||
|
||||
######################
|
||||
# Eclipse
|
||||
######################
|
||||
*.pydevproject
|
||||
.project
|
||||
.metadata
|
||||
tmp/
|
||||
tmp/**/*
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.classpath
|
||||
.settings/
|
||||
.loadpath
|
||||
.factorypath
|
||||
/src/main/resources/rebel.xml
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/**
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
######################
|
||||
# Intellij
|
||||
######################
|
||||
.idea/
|
||||
*.iml
|
||||
*.iws
|
||||
*.ipr
|
||||
*.ids
|
||||
*.orig
|
||||
|
||||
######################
|
||||
# Visual Studio Code
|
||||
######################
|
||||
.vscode/
|
||||
|
||||
######################
|
||||
# Maven
|
||||
######################
|
||||
/log/
|
||||
/target/
|
||||
|
||||
######################
|
||||
# Gradle
|
||||
######################
|
||||
.gradle/
|
||||
/build/
|
||||
|
||||
######################
|
||||
# Package Files
|
||||
######################
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
*.db
|
||||
|
||||
######################
|
||||
# Windows
|
||||
######################
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
######################
|
||||
# Mac OSX
|
||||
######################
|
||||
.DS_Store
|
||||
.svn
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear on external disk
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
|
||||
######################
|
||||
# Directories
|
||||
######################
|
||||
/bin/
|
||||
/deploy/
|
||||
|
||||
######################
|
||||
# Logs
|
||||
######################
|
||||
*.log
|
||||
|
||||
######################
|
||||
# Others
|
||||
######################
|
||||
*.class
|
||||
*.*~
|
||||
*~
|
||||
.merge_file*
|
||||
|
||||
######################
|
||||
# Gradle Wrapper
|
||||
######################
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
######################
|
||||
# Maven Wrapper
|
||||
######################
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
######################
|
||||
# ESLint
|
||||
######################
|
||||
.eslintcache
|
||||
/.apt_generated/
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
cache:
|
||||
key: "$CI_BUILD_REF_NAME"
|
||||
paths:
|
||||
- node_modules
|
||||
- .maven
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- package
|
||||
|
||||
before_script:
|
||||
- export MAVEN_USER_HOME=`pwd`/.maven
|
||||
- chmod +x mvnw
|
||||
- ./mvnw com.github.eirslett:frontend-maven-plugin:install-node-and-npm -DnodeVersion=v6.10.0 -DnpmVersion=4.3.0
|
||||
- ./mvnw com.github.eirslett:frontend-maven-plugin:npm
|
||||
|
||||
maven-build:
|
||||
stage: build
|
||||
script: ./mvnw compile -Dmaven.repo.local=$MAVEN_USER_HOME
|
||||
|
||||
maven-test:
|
||||
stage: test
|
||||
script:
|
||||
- ./mvnw test -Dmaven.repo.local=$MAVEN_USER_HOME
|
||||
artifacts:
|
||||
paths:
|
||||
- target/surefire-reports/*
|
||||
maven-front-test:
|
||||
stage: test
|
||||
script:
|
||||
- ./mvnw com.github.eirslett:frontend-maven-plugin:npm -Dfrontend.yarn.arguments=test
|
||||
artifacts:
|
||||
paths:
|
||||
- target/test-results/karma/*
|
||||
gatling-test:
|
||||
stage: test
|
||||
allow_failure: true
|
||||
script:
|
||||
- ./mvnw gatling:execute -Dmaven.repo.local=$MAVEN_USER_HOME
|
||||
before_script:
|
||||
- export MAVEN_USER_HOME=`pwd`/.maven
|
||||
- chmod +x mvnw
|
||||
- ./mvnw com.github.eirslett:frontend-maven-plugin:install-node-and-npm -DnodeVersion=v6.10.0 -DnpmVersion=4.3.0
|
||||
- ./mvnw com.github.eirslett:frontend-maven-plugin:npm
|
||||
- ./mvnw &
|
||||
artifacts:
|
||||
paths:
|
||||
- target/gatling/*
|
||||
maven-package:
|
||||
stage: package
|
||||
script:
|
||||
- ./mvnw package -Pprod -DskipTests -Dmaven.repo.local=$MAVEN_USER_HOME
|
||||
artifacts:
|
||||
paths:
|
||||
- target/*.war
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"fluentMethods": true,
|
||||
"relationships": [
|
||||
{
|
||||
"relationshipName": "post",
|
||||
"otherEntityName": "post",
|
||||
"relationshipType": "many-to-one",
|
||||
"relationshipValidateRules": [
|
||||
"required"
|
||||
],
|
||||
"otherEntityField": "title"
|
||||
}
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldName": "text",
|
||||
"fieldType": "String",
|
||||
"fieldValidateRules": [
|
||||
"required",
|
||||
"minlength",
|
||||
"maxlength"
|
||||
],
|
||||
"fieldValidateRulesMinlength": "10",
|
||||
"fieldValidateRulesMaxlength": "100"
|
||||
},
|
||||
{
|
||||
"fieldName": "creationDate",
|
||||
"fieldType": "LocalDate",
|
||||
"fieldValidateRules": [
|
||||
"required"
|
||||
]
|
||||
}
|
||||
],
|
||||
"changelogDate": "20170316224021",
|
||||
"dto": "no",
|
||||
"service": "no",
|
||||
"entityTableName": "comment",
|
||||
"pagination": "infinite-scroll"
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"fluentMethods": true,
|
||||
"relationships": [
|
||||
{
|
||||
"relationshipName": "creator",
|
||||
"otherEntityName": "user",
|
||||
"relationshipType": "many-to-one",
|
||||
"relationshipValidateRules": [
|
||||
"required"
|
||||
],
|
||||
"otherEntityField": "login",
|
||||
"ownerSide": true,
|
||||
"otherEntityRelationshipName": "post"
|
||||
}
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldName": "title",
|
||||
"fieldType": "String",
|
||||
"fieldValidateRules": [
|
||||
"required",
|
||||
"minlength",
|
||||
"maxlength"
|
||||
],
|
||||
"fieldValidateRulesMinlength": "10",
|
||||
"fieldValidateRulesMaxlength": "100"
|
||||
},
|
||||
{
|
||||
"fieldName": "content",
|
||||
"fieldType": "String",
|
||||
"fieldValidateRules": [
|
||||
"required",
|
||||
"minlength",
|
||||
"maxlength"
|
||||
],
|
||||
"fieldValidateRulesMinlength": "10",
|
||||
"fieldValidateRulesMaxlength": "1000"
|
||||
},
|
||||
{
|
||||
"fieldName": "creationDate",
|
||||
"fieldType": "LocalDate",
|
||||
"fieldValidateRules": [
|
||||
"required"
|
||||
]
|
||||
}
|
||||
],
|
||||
"changelogDate": "20170316223211",
|
||||
"dto": "no",
|
||||
"service": "no",
|
||||
"entityTableName": "post",
|
||||
"pagination": "infinite-scroll"
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip
|
|
@ -0,0 +1,41 @@
|
|||
os:
|
||||
- linux
|
||||
services:
|
||||
- docker
|
||||
language: node_js
|
||||
node_js:
|
||||
- "6.10.0"
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
sudo: false
|
||||
cache:
|
||||
directories:
|
||||
- node
|
||||
- node_modules
|
||||
- $HOME/.m2
|
||||
env:
|
||||
global:
|
||||
- NODE_VERSION=6.10.0
|
||||
- SPRING_OUTPUT_ANSI_ENABLED=ALWAYS
|
||||
- SPRING_JPA_SHOW_SQL=false
|
||||
before_install:
|
||||
- jdk_switcher use oraclejdk8
|
||||
- java -version
|
||||
- sudo /etc/init.d/mysql stop
|
||||
- sudo /etc/init.d/postgresql stop
|
||||
- nvm install $NODE_VERSION
|
||||
- npm install -g npm
|
||||
- node -v
|
||||
- npm -v
|
||||
install:
|
||||
- npm install
|
||||
script:
|
||||
- chmod +x mvnw
|
||||
- ./mvnw clean test
|
||||
- npm test
|
||||
- ./mvnw package -Pprod -DskipTests
|
||||
notifications:
|
||||
webhooks:
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"generator-jhipster": {
|
||||
"jhipsterVersion": "4.0.8",
|
||||
"baseName": "baeldung",
|
||||
"packageName": "com.baeldung",
|
||||
"packageFolder": "com/baeldung",
|
||||
"serverPort": "8080",
|
||||
"authenticationType": "jwt",
|
||||
"hibernateCache": "ehcache",
|
||||
"clusteredHttpSession": false,
|
||||
"websocket": false,
|
||||
"databaseType": "sql",
|
||||
"devDatabaseType": "h2Disk",
|
||||
"prodDatabaseType": "mysql",
|
||||
"searchEngine": false,
|
||||
"messageBroker": false,
|
||||
"serviceDiscoveryType": false,
|
||||
"buildTool": "maven",
|
||||
"enableSocialSignIn": false,
|
||||
"jwtSecretKey": "e1d4b69d3f953e3fa622121e882e6f459ca20ca4",
|
||||
"clientFramework": "angular2",
|
||||
"useSass": true,
|
||||
"clientPackageManager": "npm",
|
||||
"applicationType": "monolith",
|
||||
"testFrameworks": [
|
||||
"gatling",
|
||||
"protractor"
|
||||
],
|
||||
"jhiPrefix": "jhi",
|
||||
"enableTranslation": true,
|
||||
"nativeLanguage": "en",
|
||||
"languages": [
|
||||
"en"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env groovy
|
||||
|
||||
node {
|
||||
stage('checkout') {
|
||||
checkout scm
|
||||
}
|
||||
|
||||
stage('check java') {
|
||||
sh "java -version"
|
||||
}
|
||||
|
||||
stage('clean') {
|
||||
sh "chmod +x mvnw"
|
||||
sh "./mvnw clean"
|
||||
}
|
||||
|
||||
stage('install tools') {
|
||||
sh "./mvnw com.github.eirslett:frontend-maven-plugin:install-node-and-npm -DnodeVersion=v6.10.0 -DnpmVersion=4.3.0"
|
||||
}
|
||||
|
||||
stage('npm install') {
|
||||
sh "./mvnw com.github.eirslett:frontend-maven-plugin:npm"
|
||||
}
|
||||
|
||||
stage('backend tests') {
|
||||
try {
|
||||
sh "./mvnw test"
|
||||
} catch(err) {
|
||||
throw err
|
||||
} finally {
|
||||
junit '**/target/surefire-reports/TEST-*.xml'
|
||||
}
|
||||
}
|
||||
|
||||
stage('frontend tests') {
|
||||
try {
|
||||
sh "./mvnw com.github.eirslett:frontend-maven-plugin:npm -Dfrontend.yarn.arguments=test"
|
||||
} catch(err) {
|
||||
throw err
|
||||
} finally {
|
||||
junit '**/target/test-results/karma/TESTS-*.xml'
|
||||
}
|
||||
}
|
||||
|
||||
stage('packaging') {
|
||||
sh "./mvnw package -Pprod -DskipTests"
|
||||
archiveArtifacts artifacts: '**/target/*.war', fingerprint: true
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
# baeldung
|
||||
This application was generated using JHipster 4.0.8, you can find documentation and help at [https://jhipster.github.io/documentation-archive/v4.0.8](https://jhipster.github.io/documentation-archive/v4.0.8).
|
||||
|
||||
## Development
|
||||
|
||||
Before you can build this project, you must install and configure the following dependencies on your machine:
|
||||
|
||||
1. [Node.js][]: We use Node to run a development web server and build the project.
|
||||
Depending on your system, you can install Node either from source or as a pre-packaged bundle.
|
||||
|
||||
After installing Node, you should be able to run the following command to install development tools.
|
||||
You will only need to run this command when dependencies change in [package.json](package.json).
|
||||
|
||||
npm install
|
||||
|
||||
We use npm scripts and [Webpack][] as our build system.
|
||||
|
||||
|
||||
Run the following commands in two separate terminals to create a blissful development experience where your browser
|
||||
auto-refreshes when files change on your hard drive.
|
||||
|
||||
./mvnw
|
||||
npm start
|
||||
|
||||
[Npm][] is also used to manage CSS and JavaScript dependencies used in this application. You can upgrade dependencies by
|
||||
specifying a newer version in [package.json](package.json). You can also run `npm update` and `npm install` to manage dependencies.
|
||||
Add the `help` flag on any command to see how you can use it. For example, `npm help update`.
|
||||
|
||||
The `npm run` command will list all of the scripts available to run for this project.
|
||||
|
||||
### Managing dependencies
|
||||
|
||||
For example, to add [Leaflet][] library as a runtime dependency of your application, you would run following command:
|
||||
|
||||
npm install --save --save-exact leaflet
|
||||
|
||||
To benefit from TypeScript type definitions from [DefinitelyTyped][] repository in development, you would run following command:
|
||||
|
||||
npm install --save-dev --save-exact @types/leaflet
|
||||
|
||||
Then you would import the JS and CSS files specified in library's installation instructions so that [Webpack][] knows about them:
|
||||
|
||||
Edit [src/main/webapp/app/vendor.ts](src/main/webapp/app/vendor.ts) file:
|
||||
~~~
|
||||
import 'leaflet/dist/leaflet.js';
|
||||
~~~
|
||||
|
||||
Edit [src/main/webapp/content/css/vendor.css](src/main/webapp/content/css/vendor.css) file:
|
||||
~~~
|
||||
@import '~leaflet/dist/leaflet.css';
|
||||
~~~
|
||||
|
||||
Note: there are still few other things remaining to do for Leaflet that we won't detail here.
|
||||
|
||||
For further instructions on how to develop with JHipster, have a look at [Using JHipster in development][].
|
||||
|
||||
### Using angular-cli
|
||||
|
||||
You can also use [Angular CLI][] to generate some custom client code.
|
||||
|
||||
For example, the following command:
|
||||
|
||||
ng generate component my-component
|
||||
|
||||
will generate few files:
|
||||
|
||||
create src/main/webapp/app/my-component/my-component.component.html
|
||||
create src/main/webapp/app/my-component/my-component.component.ts
|
||||
update src/main/webapp/app/app.module.ts
|
||||
|
||||
## Building for production
|
||||
|
||||
To optimize the baeldung application for production, run:
|
||||
|
||||
./mvnw -Pprod clean package
|
||||
|
||||
This will concatenate and minify the client CSS and JavaScript files. It will also modify `index.html` so it references these new files.
|
||||
To ensure everything worked, run:
|
||||
|
||||
java -jar target/*.war
|
||||
|
||||
Then navigate to [http://localhost:8080](http://localhost:8080) in your browser.
|
||||
|
||||
Refer to [Using JHipster in production][] for more details.
|
||||
|
||||
## Testing
|
||||
|
||||
To launch your application's tests, run:
|
||||
|
||||
./mvnw clean test
|
||||
|
||||
### Client tests
|
||||
|
||||
Unit tests are run by [Karma][] and written with [Jasmine][]. They're located in [src/test/javascript/](src/test/javascript/) and can be run with:
|
||||
|
||||
npm test
|
||||
|
||||
UI end-to-end tests are powered by [Protractor][], which is built on top of WebDriverJS. They're located in [src/test/javascript/e2e](src/test/javascript/e2e)
|
||||
and can be run by starting Spring Boot in one terminal (`./mvnw spring-boot:run`) and running the tests (`gulp itest`) in a second one.
|
||||
### Other tests
|
||||
|
||||
Performance tests are run by [Gatling][] and written in Scala. They're located in [src/test/gatling](src/test/gatling) and can be run with:
|
||||
|
||||
./mvnw gatling:execute
|
||||
|
||||
For more information, refer to the [Running tests page][].
|
||||
|
||||
## Using Docker to simplify development (optional)
|
||||
|
||||
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.
|
||||
For example, to start a mysql database in a docker container, run:
|
||||
|
||||
docker-compose -f src/main/docker/mysql.yml up -d
|
||||
|
||||
To stop it and remove the container, run:
|
||||
|
||||
docker-compose -f src/main/docker/mysql.yml down
|
||||
|
||||
You can also fully dockerize your application and all the services that it depends on.
|
||||
To achieve this, first build a docker image of your app by running:
|
||||
|
||||
./mvnw package -Pprod docker:build
|
||||
|
||||
Then run:
|
||||
|
||||
docker-compose -f src/main/docker/app.yml up -d
|
||||
|
||||
For more information refer to [Using Docker and Docker-Compose][], this page also contains information on the docker-compose sub-generator (`yo jhipster:docker-compose`), which is able to generate docker configurations for one or several JHipster applications.
|
||||
|
||||
## Continuous Integration (optional)
|
||||
|
||||
To configure CI for your project, run the ci-cd sub-generator (`yo 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.
|
||||
|
||||
[JHipster Homepage and latest documentation]: https://jhipster.github.io
|
||||
[JHipster 4.0.8 archive]: https://jhipster.github.io/documentation-archive/v4.0.8
|
||||
|
||||
[Using JHipster in development]: https://jhipster.github.io/documentation-archive/v4.0.8/development/
|
||||
[Using Docker and Docker-Compose]: https://jhipster.github.io/documentation-archive/v4.0.8/docker-compose
|
||||
[Using JHipster in production]: https://jhipster.github.io/documentation-archive/v4.0.8/production/
|
||||
[Running tests page]: https://jhipster.github.io/documentation-archive/v4.0.8/running-tests/
|
||||
[Setting up Continuous Integration]: https://jhipster.github.io/documentation-archive/v4.0.8/setting-up-ci/
|
||||
|
||||
[Gatling]: http://gatling.io/
|
||||
[Node.js]: https://nodejs.org/
|
||||
[Yarn]: https://yarnpkg.org/
|
||||
[Webpack]: https://webpack.github.io/
|
||||
[Angular CLI]: https://cli.angular.io/
|
||||
[BrowserSync]: http://www.browsersync.io/
|
||||
[Karma]: http://karma-runner.github.io/
|
||||
[Jasmine]: http://jasmine.github.io/2.0/introduction.html
|
||||
[Protractor]: https://angular.github.io/protractor/
|
||||
[Leaflet]: http://leafletjs.com/
|
||||
[DefinitelyTyped]: http://definitelytyped.org/
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"project": {
|
||||
"version": "1.0.0-beta.24",
|
||||
"name": "baeldung"
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"root": "src/main/webapp/",
|
||||
"outDir": "target/www/app",
|
||||
"assets": [
|
||||
"content",
|
||||
"favicon.ico"
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "app/app.main.ts",
|
||||
"test": "",
|
||||
"tsconfig": "../../../tsconfig.json",
|
||||
"prefix": "jhi",
|
||||
"mobile": false,
|
||||
"styles": [
|
||||
"content/css/main.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"environments": {}
|
||||
}
|
||||
],
|
||||
"addons": [],
|
||||
"packages": [],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "src/test/javascript/protractor.conf.js"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"karma": {
|
||||
"config": "src/test/javascript/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"styleExt": "css",
|
||||
"prefixInterfaces": false,
|
||||
"inline": {
|
||||
"style": true,
|
||||
"template": false
|
||||
},
|
||||
"spec": {
|
||||
"class": false,
|
||||
"component": false,
|
||||
"directive": false,
|
||||
"module": false,
|
||||
"pipe": false,
|
||||
"service": false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
machine:
|
||||
services:
|
||||
- docker
|
||||
java:
|
||||
version: oraclejdk8
|
||||
node:
|
||||
version: 6.10.0
|
||||
dependencies:
|
||||
cache_directories:
|
||||
- node
|
||||
- node_modules
|
||||
- ~/.m2
|
||||
override:
|
||||
- java -version
|
||||
- npm install -g npm
|
||||
- node -v
|
||||
- npm -v
|
||||
- java -version
|
||||
- npm install
|
||||
test:
|
||||
override:
|
||||
- chmod +x mvnw
|
||||
- ./mvnw clean test
|
||||
- npm test
|
||||
- ./mvnw package -Pprod -DskipTests
|
|
@ -0,0 +1,233 @@
|
|||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
#
|
||||
# Look for the Apple JDKs first to preserve the existing behaviour, and then look
|
||||
# for the new JDKs provided by Oracle.
|
||||
#
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
|
||||
#
|
||||
# Oracle JDKs
|
||||
#
|
||||
export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=`/usr/libexec/java_home`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Migwn, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
# TODO classpath?
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`which java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
local basedir=$(pwd)
|
||||
local wdir=$(pwd)
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
wdir=$(cd "$wdir/.."; pwd)
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} "$@"
|
|
@ -0,0 +1,145 @@
|
|||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
|
||||
set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar""
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
|
@ -0,0 +1,112 @@
|
|||
{
|
||||
"name": "baeldung",
|
||||
"version": "0.0.0",
|
||||
"description": "Description for baeldung",
|
||||
"private": true,
|
||||
"cacheDirectories": [
|
||||
"node_modules"
|
||||
],
|
||||
"dependencies": {
|
||||
"@angular/common": "2.4.7",
|
||||
"@angular/compiler": "2.4.7",
|
||||
"@angular/core": "2.4.7",
|
||||
"@angular/forms": "2.4.7",
|
||||
"@angular/http": "2.4.7",
|
||||
"@angular/platform-browser": "2.4.7",
|
||||
"@angular/platform-browser-dynamic": "2.4.7",
|
||||
"@angular/router": "3.4.7",
|
||||
"@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.20",
|
||||
"angular2-infinite-scroll": "0.3.0",
|
||||
"bootstrap": "4.0.0-alpha.6",
|
||||
"font-awesome": "4.7.0",
|
||||
"angular2-cookie": "1.2.6",
|
||||
"core-js": "2.4.1",
|
||||
"jquery": "3.1.1",
|
||||
"ng-jhipster": "0.1.9",
|
||||
"ng2-webstorage": "1.5.0",
|
||||
"reflect-metadata": "0.1.9",
|
||||
"rxjs": "5.1.0",
|
||||
"swagger-ui": "2.2.10",
|
||||
"tether": "1.4.0",
|
||||
"zone.js": "0.7.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.0.0-beta.28.3",
|
||||
"@types/jasmine": "2.5.42",
|
||||
"@types/node": "7.0.5",
|
||||
"@types/selenium-webdriver": "2.53.39",
|
||||
"add-asset-html-webpack-plugin": "1.0.2",
|
||||
"angular2-template-loader": "0.6.2",
|
||||
"awesome-typescript-loader": "3.0.7",
|
||||
"browser-sync": "2.18.7",
|
||||
"browser-sync-webpack-plugin": "1.1.4",
|
||||
"codelyzer": "2.0.0",
|
||||
"copy-webpack-plugin": "4.0.1",
|
||||
"css-loader": "0.26.1",
|
||||
"del": "2.2.2",
|
||||
"event-stream": "3.3.4",
|
||||
"exports-loader": "0.6.3",
|
||||
"extract-text-webpack-plugin": "2.0.0-beta.5",
|
||||
"file-loader": "0.10.0",
|
||||
"generator-jhipster": "4.0.8",
|
||||
"html-webpack-plugin": "2.28.0",
|
||||
"image-webpack-loader": "3.2.0",
|
||||
"jasmine-core": "2.5.2",
|
||||
"jasmine-reporters": "2.2.0",
|
||||
"karma": "1.4.1",
|
||||
"karma-chrome-launcher": "2.0.0",
|
||||
"karma-coverage": "1.1.1",
|
||||
"karma-intl-shim": "1.0.3",
|
||||
"karma-jasmine": "1.1.0",
|
||||
"karma-junit-reporter": "1.2.0",
|
||||
"karma-phantomjs-launcher": "1.0.2",
|
||||
"karma-remap-istanbul": "0.6.0",
|
||||
"karma-sourcemap-loader": "0.3.7",
|
||||
"karma-webpack": "2.0.2",
|
||||
"lazypipe": "1.0.1",
|
||||
"lodash": "4.17.4",
|
||||
"map-stream": "0.0.6",
|
||||
"phantomjs-prebuilt": "2.1.14",
|
||||
"protractor": "5.1.1",
|
||||
"protractor-jasmine2-screenshot-reporter": "0.3.3",
|
||||
"ts-node": "2.1.0",
|
||||
"proxy-middleware": "0.15.0",
|
||||
"raw-loader": "0.5.1",
|
||||
"run-sequence": "1.2.2",
|
||||
"sourcemap-istanbul-instrumenter-loader": "0.2.0",
|
||||
"string-replace-webpack-plugin": "0.0.5",
|
||||
"style-loader": "0.13.1",
|
||||
"to-string-loader": "1.1.5",
|
||||
"tslint": "4.4.2",
|
||||
"tslint-loader": "3.4.1",
|
||||
"typescript": "2.1.6",
|
||||
"webpack": "2.2.1",
|
||||
"webpack-dev-server": "2.3.0",
|
||||
"webpack-merge": "2.6.1",
|
||||
"webpack-visualizer-plugin": "0.1.10",
|
||||
"write-file-webpack-plugin": "3.4.2",
|
||||
"xml2js": "0.4.17",
|
||||
"sass-loader": "5.0.1",
|
||||
"node-sass": "4.5.0",
|
||||
"postcss-loader": "1.3.0",
|
||||
"yargs": "6.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "tslint 'src/main/webapp/app/**/*.ts' --force",
|
||||
"lint:fix": "tslint 'src/main/webapp/app/**/*.ts' --fix --force",
|
||||
"tsc": "tsc",
|
||||
"tsc:w": "tsc -w",
|
||||
"start": "npm run webpack:dev",
|
||||
"webpack:build": "webpack --config webpack/webpack.vendor.js && webpack --config webpack/webpack.dev.js",
|
||||
"webpack:build:dev": "webpack --config webpack/webpack.dev.js",
|
||||
"webpack:dev": "webpack-dev-server --config webpack/webpack.dev.js --progress --inline --hot --profile --port=9060",
|
||||
"webpack:prod": "npm test && webpack -p --config webpack/webpack.vendor.js && webpack -p --config webpack/webpack.prod.js",
|
||||
"test": "npm run lint && karma start src/test/javascript/karma.conf.js",
|
||||
"test:watch": "karma start --watch",
|
||||
"e2e": "protractor src/test/javascript/protractor.conf.js",
|
||||
"postinstall": "webdriver-manager update && npm run webpack:build"
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
plugins: []
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
FROM openjdk:8-jre-alpine
|
||||
|
||||
ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \
|
||||
JHIPSTER_SLEEP=0
|
||||
|
||||
# add directly the war
|
||||
ADD *.war /app.war
|
||||
|
||||
VOLUME /tmp
|
||||
EXPOSE 8080
|
||||
CMD echo "The application will start in ${JHIPSTER_SLEEP}s..." && \
|
||||
sleep ${JHIPSTER_SLEEP} && \
|
||||
java -Djava.security.egd=file:/dev/./urandom -jar /app.war
|
|
@ -0,0 +1,14 @@
|
|||
version: '2'
|
||||
services:
|
||||
baeldung-app:
|
||||
image: baeldung
|
||||
environment:
|
||||
- SPRING_PROFILES_ACTIVE=prod,swagger
|
||||
- SPRING_DATASOURCE_URL=jdbc:mysql://baeldung-mysql:3306/baeldung?useUnicode=true&characterEncoding=utf8&useSSL=false
|
||||
- JHIPSTER_SLEEP=10 # gives time for the database to boot before the application
|
||||
ports:
|
||||
- 8080:8080
|
||||
baeldung-mysql:
|
||||
extends:
|
||||
file: mysql.yml
|
||||
service: baeldung-mysql
|
|
@ -0,0 +1,13 @@
|
|||
version: '2'
|
||||
services:
|
||||
baeldung-mysql:
|
||||
image: mysql:5.7.13
|
||||
# volumes:
|
||||
# - ~/volumes/jhipster/baeldung/mysql/:/var/lib/mysql/
|
||||
environment:
|
||||
- MYSQL_USER=root
|
||||
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
|
||||
- MYSQL_DATABASE=baeldung
|
||||
ports:
|
||||
- 3306:3306
|
||||
command: mysqld --lower_case_table_names=1 --skip-ssl --character_set_server=utf8
|
|
@ -0,0 +1,7 @@
|
|||
version: '2'
|
||||
services:
|
||||
baeldung-sonar:
|
||||
image: sonarqube:6.2-alpine
|
||||
ports:
|
||||
- 9000:9000
|
||||
- 9092:9092
|
|
@ -0,0 +1,21 @@
|
|||
package com.baeldung;
|
||||
|
||||
import com.baeldung.config.DefaultProfileUtil;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.support.SpringBootServletInitializer;
|
||||
|
||||
/**
|
||||
* This is a helper Java class that provides an alternative to creating a web.xml.
|
||||
* This will be invoked only when the application is deployed to a servlet container like Tomcat, JBoss etc.
|
||||
*/
|
||||
public class ApplicationWebXml extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
/**
|
||||
* set a default to use when no profile is configured.
|
||||
*/
|
||||
DefaultProfileUtil.addDefaultProfile(application.application());
|
||||
return application.sources(BaeldungApp.class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package com.baeldung;
|
||||
|
||||
import com.baeldung.config.ApplicationProperties;
|
||||
import com.baeldung.config.DefaultProfileUtil;
|
||||
|
||||
import io.github.jhipster.config.JHipsterConstants;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.actuate.autoconfigure.*;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
@ComponentScan
|
||||
@EnableAutoConfiguration(exclude = {MetricFilterAutoConfiguration.class, MetricRepositoryAutoConfiguration.class})
|
||||
@EnableConfigurationProperties({LiquibaseProperties.class, ApplicationProperties.class})
|
||||
public class BaeldungApp {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BaeldungApp.class);
|
||||
|
||||
private final Environment env;
|
||||
|
||||
public BaeldungApp(Environment env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes baeldung.
|
||||
* <p>
|
||||
* Spring profiles can be configured with a program arguments --spring.profiles.active=your-active-profile
|
||||
* <p>
|
||||
* You can find more information on how profiles work with JHipster on <a href="http://jhipster.github.io/profiles/">http://jhipster.github.io/profiles/</a>.
|
||||
*/
|
||||
@PostConstruct
|
||||
public void initApplication() {
|
||||
Collection<String> activeProfiles = Arrays.asList(env.getActiveProfiles());
|
||||
if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) {
|
||||
log.error("You have misconfigured your application! It should not run " +
|
||||
"with both the 'dev' and 'prod' profiles at the same time.");
|
||||
}
|
||||
if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_CLOUD)) {
|
||||
log.error("You have misconfigured your application! It should not" +
|
||||
"run with both the 'dev' and 'cloud' profiles at the same time.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main method, used to run the application.
|
||||
*
|
||||
* @param args the command line arguments
|
||||
* @throws UnknownHostException if the local host name could not be resolved into an address
|
||||
*/
|
||||
public static void main(String[] args) throws UnknownHostException {
|
||||
SpringApplication app = new SpringApplication(BaeldungApp.class);
|
||||
DefaultProfileUtil.addDefaultProfile(app);
|
||||
Environment env = app.run(args).getEnvironment();
|
||||
String protocol = "http";
|
||||
if (env.getProperty("server.ssl.key-store") != null) {
|
||||
protocol = "https";
|
||||
}
|
||||
log.info("\n----------------------------------------------------------\n\t" +
|
||||
"Application '{}' is running! Access URLs:\n\t" +
|
||||
"Local: \t\t{}://localhost:{}\n\t" +
|
||||
"External: \t{}://{}:{}\n\t" +
|
||||
"Profile(s): \t{}\n----------------------------------------------------------",
|
||||
env.getProperty("spring.application.name"),
|
||||
protocol,
|
||||
env.getProperty("server.port"),
|
||||
protocol,
|
||||
InetAddress.getLocalHost().getHostAddress(),
|
||||
env.getProperty("server.port"),
|
||||
env.getActiveProfiles());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package com.baeldung.aop.logging;
|
||||
|
||||
import io.github.jhipster.config.JHipsterConstants;
|
||||
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Aspect for logging execution of service and repository Spring components.
|
||||
*
|
||||
* By default, it only runs with the "dev" profile.
|
||||
*/
|
||||
@Aspect
|
||||
public class LoggingAspect {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final Environment env;
|
||||
|
||||
public LoggingAspect(Environment env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pointcut that matches all repositories, services and Web REST endpoints.
|
||||
*/
|
||||
@Pointcut("within(com.baeldung.repository..*) || within(com.baeldung.service..*) || within(com.baeldung.web.rest..*)")
|
||||
public void loggingPointcut() {
|
||||
// Method is empty as this is just a Pointcut, the implementations are in the advices.
|
||||
}
|
||||
|
||||
/**
|
||||
* Advice that logs methods throwing exceptions.
|
||||
*/
|
||||
@AfterThrowing(pointcut = "loggingPointcut()", throwing = "e")
|
||||
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
|
||||
if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) {
|
||||
log.error("Exception in {}.{}() with cause = \'{}\' and exception = \'{}\'", joinPoint.getSignature().getDeclaringTypeName(),
|
||||
joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL", e.getMessage(), e);
|
||||
|
||||
} else {
|
||||
log.error("Exception in {}.{}() with cause = {}", joinPoint.getSignature().getDeclaringTypeName(),
|
||||
joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Advice that logs when a method is entered and exited.
|
||||
*/
|
||||
@Around("loggingPointcut()")
|
||||
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Enter: {}.{}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(),
|
||||
joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
|
||||
}
|
||||
try {
|
||||
Object result = joinPoint.proceed();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Exit: {}.{}() with result = {}", joinPoint.getSignature().getDeclaringTypeName(),
|
||||
joinPoint.getSignature().getName(), result);
|
||||
}
|
||||
return result;
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("Illegal argument: {} in {}.{}()", Arrays.toString(joinPoint.getArgs()),
|
||||
joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Properties specific to JHipster.
|
||||
*
|
||||
* <p>
|
||||
* Properties are configured in the application.yml file.
|
||||
* </p>
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "application", ignoreUnknownFields = false)
|
||||
public class ApplicationProperties {
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import io.github.jhipster.async.ExceptionHandlingAsyncTaskExecutor;
|
||||
import io.github.jhipster.config.JHipsterProperties;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.*;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
@EnableScheduling
|
||||
public class AsyncConfiguration implements AsyncConfigurer {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);
|
||||
|
||||
private final JHipsterProperties jHipsterProperties;
|
||||
|
||||
public AsyncConfiguration(JHipsterProperties jHipsterProperties) {
|
||||
this.jHipsterProperties = jHipsterProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean(name = "taskExecutor")
|
||||
public Executor getAsyncExecutor() {
|
||||
log.debug("Creating Async Task Executor");
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize());
|
||||
executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize());
|
||||
executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity());
|
||||
executor.setThreadNamePrefix("baeldung-Executor-");
|
||||
return new ExceptionHandlingAsyncTaskExecutor(executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
|
||||
return new SimpleAsyncUncaughtExceptionHandler();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import io.github.jhipster.config.JHipsterProperties;
|
||||
import org.ehcache.config.builders.CacheConfigurationBuilder;
|
||||
import org.ehcache.config.builders.ResourcePoolsBuilder;
|
||||
import org.ehcache.expiry.Duration;
|
||||
import org.ehcache.expiry.Expirations;
|
||||
import org.ehcache.jsr107.Eh107Configuration;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.*;
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
@AutoConfigureAfter(value = { MetricsConfiguration.class })
|
||||
@AutoConfigureBefore(value = { WebConfigurer.class, DatabaseConfiguration.class })
|
||||
public class CacheConfiguration {
|
||||
|
||||
private final javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration;
|
||||
|
||||
public CacheConfiguration(JHipsterProperties jHipsterProperties) {
|
||||
JHipsterProperties.Cache.Ehcache ehcache =
|
||||
jHipsterProperties.getCache().getEhcache();
|
||||
|
||||
jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(
|
||||
CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class,
|
||||
ResourcePoolsBuilder.heap(ehcache.getMaxEntries()))
|
||||
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(ehcache.getTimeToLiveSeconds(), TimeUnit.SECONDS)))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JCacheManagerCustomizer cacheManagerCustomizer() {
|
||||
return cm -> {
|
||||
cm.createCache(com.baeldung.domain.User.class.getName(), jcacheConfiguration);
|
||||
cm.createCache(com.baeldung.domain.Authority.class.getName(), jcacheConfiguration);
|
||||
cm.createCache(com.baeldung.domain.User.class.getName() + ".authorities", jcacheConfiguration);
|
||||
cm.createCache(com.baeldung.domain.Post.class.getName(), jcacheConfiguration);
|
||||
cm.createCache(com.baeldung.domain.Comment.class.getName(), jcacheConfiguration);
|
||||
// jhipster-needle-ehcache-add-entry
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import io.github.jhipster.config.JHipsterConstants;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cloud.config.java.AbstractCloudConfig;
|
||||
import org.springframework.context.annotation.*;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Configuration
|
||||
@Profile(JHipsterConstants.SPRING_PROFILE_CLOUD)
|
||||
public class CloudDatabaseConfiguration extends AbstractCloudConfig {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(CloudDatabaseConfiguration.class);
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
log.info("Configuring JDBC datasource from a cloud provider");
|
||||
return connectionFactory().dataSource();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
/**
|
||||
* Application constants.
|
||||
*/
|
||||
public final class Constants {
|
||||
|
||||
//Regex for acceptable logins
|
||||
public static final String LOGIN_REGEX = "^[_'.@A-Za-z0-9-]*$";
|
||||
|
||||
public static final String SYSTEM_ACCOUNT = "system";
|
||||
public static final String ANONYMOUS_USER = "anonymoususer";
|
||||
|
||||
private Constants() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import io.github.jhipster.config.JHipsterConstants;
|
||||
import io.github.jhipster.config.liquibase.AsyncSpringLiquibase;
|
||||
|
||||
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
|
||||
import liquibase.integration.spring.SpringLiquibase;
|
||||
import org.h2.tools.Server;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@Configuration
|
||||
@EnableJpaRepositories("com.baeldung.repository")
|
||||
@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
|
||||
@EnableTransactionManagement
|
||||
public class DatabaseConfiguration {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);
|
||||
|
||||
private final Environment env;
|
||||
|
||||
public DatabaseConfiguration(Environment env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the TCP port for the H2 database, so it is available remotely.
|
||||
*
|
||||
* @return the H2 database TCP server
|
||||
* @throws SQLException if the server failed to start
|
||||
*/
|
||||
@Bean(initMethod = "start", destroyMethod = "stop")
|
||||
@Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
|
||||
public Server h2TCPServer() throws SQLException {
|
||||
return Server.createTcpServer("-tcp","-tcpAllowOthers");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SpringLiquibase liquibase(@Qualifier("taskExecutor") TaskExecutor taskExecutor,
|
||||
DataSource dataSource, LiquibaseProperties liquibaseProperties) {
|
||||
|
||||
// Use liquibase.integration.spring.SpringLiquibase if you don't want Liquibase to start asynchronously
|
||||
SpringLiquibase liquibase = new AsyncSpringLiquibase(taskExecutor, env);
|
||||
liquibase.setDataSource(dataSource);
|
||||
liquibase.setChangeLog("classpath:config/liquibase/master.xml");
|
||||
liquibase.setContexts(liquibaseProperties.getContexts());
|
||||
liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema());
|
||||
liquibase.setDropFirst(liquibaseProperties.isDropFirst());
|
||||
if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE)) {
|
||||
liquibase.setShouldRun(false);
|
||||
} else {
|
||||
liquibase.setShouldRun(liquibaseProperties.isEnabled());
|
||||
log.debug("Configuring Liquibase");
|
||||
}
|
||||
return liquibase;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Hibernate5Module hibernate5Module() {
|
||||
return new Hibernate5Module();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
@Configuration
|
||||
public class DateTimeFormatConfiguration extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public void addFormatters(FormatterRegistry registry) {
|
||||
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
|
||||
registrar.setUseIsoFormat(true);
|
||||
registrar.registerFormatters(registry);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import io.github.jhipster.config.JHipsterConstants;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Utility class to load a Spring profile to be used as default
|
||||
* when there is no <code>spring.profiles.active</code> set in the environment or as command line argument.
|
||||
* If the value is not available in <code>application.yml</code> then <code>dev</code> profile will be used as default.
|
||||
*/
|
||||
public final class DefaultProfileUtil {
|
||||
|
||||
private static final String SPRING_PROFILE_DEFAULT = "spring.profiles.default";
|
||||
|
||||
private DefaultProfileUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a default to use when no profile is configured.
|
||||
*
|
||||
* @param app the Spring application
|
||||
*/
|
||||
public static void addDefaultProfile(SpringApplication app) {
|
||||
Map<String, Object> defProperties = new HashMap<>();
|
||||
/*
|
||||
* The default profile to use when no other profiles are defined
|
||||
* This cannot be set in the <code>application.yml</code> file.
|
||||
* See https://github.com/spring-projects/spring-boot/issues/1219
|
||||
*/
|
||||
defProperties.put(SPRING_PROFILE_DEFAULT, JHipsterConstants.SPRING_PROFILE_DEVELOPMENT);
|
||||
app.setDefaultProperties(defProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the profiles that are applied else get default profiles.
|
||||
*/
|
||||
public static String[] getActiveProfiles(Environment env) {
|
||||
String[] profiles = env.getActiveProfiles();
|
||||
if (profiles.length == 0) {
|
||||
return env.getDefaultProfiles();
|
||||
}
|
||||
return profiles;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import io.github.jhipster.config.locale.AngularCookieLocaleResolver;
|
||||
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||
|
||||
@Configuration
|
||||
public class LocaleConfiguration extends WebMvcConfigurerAdapter implements EnvironmentAware {
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
// unused
|
||||
}
|
||||
|
||||
@Bean(name = "localeResolver")
|
||||
public LocaleResolver localeResolver() {
|
||||
AngularCookieLocaleResolver cookieLocaleResolver = new AngularCookieLocaleResolver();
|
||||
cookieLocaleResolver.setCookieName("NG_TRANSLATE_LANG_KEY");
|
||||
return cookieLocaleResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
|
||||
localeChangeInterceptor.setParamName("language");
|
||||
registry.addInterceptor(localeChangeInterceptor);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import com.baeldung.aop.logging.LoggingAspect;
|
||||
|
||||
import io.github.jhipster.config.JHipsterConstants;
|
||||
|
||||
import org.springframework.context.annotation.*;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
@Configuration
|
||||
@EnableAspectJAutoProxy
|
||||
public class LoggingAspectConfiguration {
|
||||
|
||||
@Bean
|
||||
@Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
|
||||
public LoggingAspect loggingAspect(Environment env) {
|
||||
return new LoggingAspect(env);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import io.github.jhipster.config.JHipsterProperties;
|
||||
|
||||
import ch.qos.logback.classic.AsyncAppender;
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.spi.LoggerContextListener;
|
||||
import ch.qos.logback.core.spi.ContextAwareBase;
|
||||
import net.logstash.logback.appender.LogstashSocketAppender;
|
||||
import net.logstash.logback.stacktrace.ShortenedThrowableConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class LoggingConfiguration {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(LoggingConfiguration.class);
|
||||
|
||||
private LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
|
||||
@Value("${spring.application.name}")
|
||||
private String appName;
|
||||
|
||||
@Value("${server.port}")
|
||||
private String serverPort;
|
||||
|
||||
private final JHipsterProperties jHipsterProperties;
|
||||
|
||||
public LoggingConfiguration(JHipsterProperties jHipsterProperties) {
|
||||
this.jHipsterProperties = jHipsterProperties;
|
||||
if (jHipsterProperties.getLogging().getLogstash().isEnabled()) {
|
||||
addLogstashAppender(context);
|
||||
|
||||
// Add context listener
|
||||
LogbackLoggerContextListener loggerContextListener = new LogbackLoggerContextListener();
|
||||
loggerContextListener.setContext(context);
|
||||
context.addListener(loggerContextListener);
|
||||
}
|
||||
}
|
||||
|
||||
public void addLogstashAppender(LoggerContext context) {
|
||||
log.info("Initializing Logstash logging");
|
||||
|
||||
LogstashSocketAppender logstashAppender = new LogstashSocketAppender();
|
||||
logstashAppender.setName("LOGSTASH");
|
||||
logstashAppender.setContext(context);
|
||||
String customFields = "{\"app_name\":\"" + appName + "\",\"app_port\":\"" + serverPort + "\"}";
|
||||
|
||||
// Set the Logstash appender config from JHipster properties
|
||||
logstashAppender.setSyslogHost(jHipsterProperties.getLogging().getLogstash().getHost());
|
||||
logstashAppender.setPort(jHipsterProperties.getLogging().getLogstash().getPort());
|
||||
logstashAppender.setCustomFields(customFields);
|
||||
|
||||
// Limit the maximum length of the forwarded stacktrace so that it won't exceed the 8KB UDP limit of logstash
|
||||
ShortenedThrowableConverter throwableConverter = new ShortenedThrowableConverter();
|
||||
throwableConverter.setMaxLength(7500);
|
||||
throwableConverter.setRootCauseFirst(true);
|
||||
logstashAppender.setThrowableConverter(throwableConverter);
|
||||
|
||||
logstashAppender.start();
|
||||
|
||||
// Wrap the appender in an Async appender for performance
|
||||
AsyncAppender asyncLogstashAppender = new AsyncAppender();
|
||||
asyncLogstashAppender.setContext(context);
|
||||
asyncLogstashAppender.setName("ASYNC_LOGSTASH");
|
||||
asyncLogstashAppender.setQueueSize(jHipsterProperties.getLogging().getLogstash().getQueueSize());
|
||||
asyncLogstashAppender.addAppender(logstashAppender);
|
||||
asyncLogstashAppender.start();
|
||||
|
||||
context.getLogger("ROOT").addAppender(asyncLogstashAppender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logback configuration is achieved by configuration file and API.
|
||||
* When configuration file change is detected, the configuration is reset.
|
||||
* This listener ensures that the programmatic configuration is also re-applied after reset.
|
||||
*/
|
||||
class LogbackLoggerContextListener extends ContextAwareBase implements LoggerContextListener {
|
||||
|
||||
@Override
|
||||
public boolean isResetResistant() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(LoggerContext context) {
|
||||
addLogstashAppender(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReset(LoggerContext context) {
|
||||
addLogstashAppender(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop(LoggerContext context) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLevelChange(ch.qos.logback.classic.Logger logger, Level level) {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import io.github.jhipster.config.JHipsterProperties;
|
||||
import io.github.jhipster.config.jcache.JCacheGaugeSet;
|
||||
|
||||
import com.codahale.metrics.JmxReporter;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.codahale.metrics.Slf4jReporter;
|
||||
import com.codahale.metrics.health.HealthCheckRegistry;
|
||||
import com.codahale.metrics.jvm.*;
|
||||
import com.ryantenney.metrics.spring.config.annotation.EnableMetrics;
|
||||
import com.ryantenney.metrics.spring.config.annotation.MetricsConfigurerAdapter;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.*;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Configuration
|
||||
@EnableMetrics(proxyTargetClass = true)
|
||||
public class MetricsConfiguration extends MetricsConfigurerAdapter {
|
||||
|
||||
private static final String PROP_METRIC_REG_JVM_MEMORY = "jvm.memory";
|
||||
private static final String PROP_METRIC_REG_JVM_GARBAGE = "jvm.garbage";
|
||||
private static final String PROP_METRIC_REG_JVM_THREADS = "jvm.threads";
|
||||
private static final String PROP_METRIC_REG_JVM_FILES = "jvm.files";
|
||||
private static final String PROP_METRIC_REG_JVM_BUFFERS = "jvm.buffers";
|
||||
|
||||
private static final String PROP_METRIC_REG_JCACHE_STATISTICS = "jcache.statistics";
|
||||
private final Logger log = LoggerFactory.getLogger(MetricsConfiguration.class);
|
||||
|
||||
private MetricRegistry metricRegistry = new MetricRegistry();
|
||||
|
||||
private HealthCheckRegistry healthCheckRegistry = new HealthCheckRegistry();
|
||||
|
||||
private final JHipsterProperties jHipsterProperties;
|
||||
|
||||
private HikariDataSource hikariDataSource;
|
||||
|
||||
public MetricsConfiguration(JHipsterProperties jHipsterProperties) {
|
||||
this.jHipsterProperties = jHipsterProperties;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setHikariDataSource(HikariDataSource hikariDataSource) {
|
||||
this.hikariDataSource = hikariDataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public MetricRegistry getMetricRegistry() {
|
||||
return metricRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public HealthCheckRegistry getHealthCheckRegistry() {
|
||||
return healthCheckRegistry;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
log.debug("Registering JVM gauges");
|
||||
metricRegistry.register(PROP_METRIC_REG_JVM_MEMORY, new MemoryUsageGaugeSet());
|
||||
metricRegistry.register(PROP_METRIC_REG_JVM_GARBAGE, new GarbageCollectorMetricSet());
|
||||
metricRegistry.register(PROP_METRIC_REG_JVM_THREADS, new ThreadStatesGaugeSet());
|
||||
metricRegistry.register(PROP_METRIC_REG_JVM_FILES, new FileDescriptorRatioGauge());
|
||||
metricRegistry.register(PROP_METRIC_REG_JVM_BUFFERS, new BufferPoolMetricSet(ManagementFactory.getPlatformMBeanServer()));
|
||||
|
||||
metricRegistry.register(PROP_METRIC_REG_JCACHE_STATISTICS, new JCacheGaugeSet());
|
||||
if (hikariDataSource != null) {
|
||||
log.debug("Monitoring the datasource");
|
||||
hikariDataSource.setMetricRegistry(metricRegistry);
|
||||
}
|
||||
if (jHipsterProperties.getMetrics().getJmx().isEnabled()) {
|
||||
log.debug("Initializing Metrics JMX reporting");
|
||||
JmxReporter jmxReporter = JmxReporter.forRegistry(metricRegistry).build();
|
||||
jmxReporter.start();
|
||||
}
|
||||
if (jHipsterProperties.getMetrics().getLogs().isEnabled()) {
|
||||
log.info("Initializing Metrics Log reporting");
|
||||
final Slf4jReporter reporter = Slf4jReporter.forRegistry(metricRegistry)
|
||||
.outputTo(LoggerFactory.getLogger("metrics"))
|
||||
.convertRatesTo(TimeUnit.SECONDS)
|
||||
.convertDurationsTo(TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
reporter.start(jHipsterProperties.getMetrics().getLogs().getReportFrequency(), TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import com.baeldung.security.*;
|
||||
import com.baeldung.security.jwt.*;
|
||||
|
||||
import io.github.jhipster.security.*;
|
||||
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
|
||||
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final AuthenticationManagerBuilder authenticationManagerBuilder;
|
||||
|
||||
private final UserDetailsService userDetailsService;
|
||||
|
||||
private final TokenProvider tokenProvider;
|
||||
|
||||
private final CorsFilter corsFilter;
|
||||
|
||||
public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, UserDetailsService userDetailsService,
|
||||
TokenProvider tokenProvider,
|
||||
CorsFilter corsFilter) {
|
||||
|
||||
this.authenticationManagerBuilder = authenticationManagerBuilder;
|
||||
this.userDetailsService = userDetailsService;
|
||||
this.tokenProvider = tokenProvider;
|
||||
this.corsFilter = corsFilter;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
try {
|
||||
authenticationManagerBuilder
|
||||
.userDetailsService(userDetailsService)
|
||||
.passwordEncoder(passwordEncoder());
|
||||
} catch (Exception e) {
|
||||
throw new BeanInitializationException("Security configuration failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Http401UnauthorizedEntryPoint http401UnauthorizedEntryPoint() {
|
||||
return new Http401UnauthorizedEntryPoint();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web.ignoring()
|
||||
.antMatchers(HttpMethod.OPTIONS, "/**")
|
||||
.antMatchers("/app/**/*.{js,html}")
|
||||
.antMatchers("/bower_components/**")
|
||||
.antMatchers("/i18n/**")
|
||||
.antMatchers("/content/**")
|
||||
.antMatchers("/swagger-ui/index.html")
|
||||
.antMatchers("/test/**")
|
||||
.antMatchers("/h2-console/**");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(http401UnauthorizedEntryPoint())
|
||||
.and()
|
||||
.csrf()
|
||||
.disable()
|
||||
.headers()
|
||||
.frameOptions()
|
||||
.disable()
|
||||
.and()
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.antMatchers("/api/register").permitAll()
|
||||
.antMatchers("/api/activate").permitAll()
|
||||
.antMatchers("/api/authenticate").permitAll()
|
||||
.antMatchers("/api/account/reset_password/init").permitAll()
|
||||
.antMatchers("/api/account/reset_password/finish").permitAll()
|
||||
.antMatchers("/api/profile-info").permitAll()
|
||||
.antMatchers("/api/**").authenticated()
|
||||
.antMatchers("/management/health").permitAll()
|
||||
.antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
|
||||
.antMatchers("/v2/api-docs/**").permitAll()
|
||||
.antMatchers("/swagger-resources/configuration/ui").permitAll()
|
||||
.antMatchers("/swagger-ui/index.html").hasAuthority(AuthoritiesConstants.ADMIN)
|
||||
.and()
|
||||
.apply(securityConfigurerAdapter());
|
||||
|
||||
}
|
||||
|
||||
private JWTConfigurer securityConfigurerAdapter() {
|
||||
return new JWTConfigurer(tokenProvider);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
|
||||
return new SecurityEvaluationContextExtension();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import org.apache.commons.lang3.CharEncoding;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.*;
|
||||
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
|
||||
|
||||
@Configuration
|
||||
public class ThymeleafConfiguration {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Logger log = LoggerFactory.getLogger(ThymeleafConfiguration.class);
|
||||
|
||||
@Bean
|
||||
@Description("Thymeleaf template resolver serving HTML 5 emails")
|
||||
public ClassLoaderTemplateResolver emailTemplateResolver() {
|
||||
ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver();
|
||||
emailTemplateResolver.setPrefix("mails/");
|
||||
emailTemplateResolver.setSuffix(".html");
|
||||
emailTemplateResolver.setTemplateMode("HTML5");
|
||||
emailTemplateResolver.setCharacterEncoding(CharEncoding.UTF_8);
|
||||
emailTemplateResolver.setOrder(1);
|
||||
return emailTemplateResolver;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import io.github.jhipster.config.JHipsterConstants;
|
||||
import io.github.jhipster.config.JHipsterProperties;
|
||||
import io.github.jhipster.web.filter.CachingHttpHeadersFilter;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.codahale.metrics.servlet.InstrumentedFilter;
|
||||
import com.codahale.metrics.servlets.MetricsServlet;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.embedded.*;
|
||||
import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory;
|
||||
import io.undertow.UndertowOptions;
|
||||
import org.springframework.boot.web.servlet.ServletContextInitializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import javax.servlet.*;
|
||||
|
||||
/**
|
||||
* Configuration of web application with Servlet 3.0 APIs.
|
||||
*/
|
||||
@Configuration
|
||||
public class WebConfigurer implements ServletContextInitializer, EmbeddedServletContainerCustomizer {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(WebConfigurer.class);
|
||||
|
||||
private final Environment env;
|
||||
|
||||
private final JHipsterProperties jHipsterProperties;
|
||||
|
||||
private MetricRegistry metricRegistry;
|
||||
|
||||
public WebConfigurer(Environment env, JHipsterProperties jHipsterProperties) {
|
||||
|
||||
this.env = env;
|
||||
this.jHipsterProperties = jHipsterProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext servletContext) throws ServletException {
|
||||
if (env.getActiveProfiles().length != 0) {
|
||||
log.info("Web application configuration, using profiles: {}", (Object[]) env.getActiveProfiles());
|
||||
}
|
||||
EnumSet<DispatcherType> disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC);
|
||||
initMetrics(servletContext, disps);
|
||||
if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) {
|
||||
initCachingHttpHeadersFilter(servletContext, disps);
|
||||
}
|
||||
if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) {
|
||||
initH2Console(servletContext);
|
||||
}
|
||||
log.info("Web application fully configured");
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize the Servlet engine: Mime types, the document root, the cache.
|
||||
*/
|
||||
@Override
|
||||
public void customize(ConfigurableEmbeddedServletContainer container) {
|
||||
MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
|
||||
// IE issue, see https://github.com/jhipster/generator-jhipster/pull/711
|
||||
mappings.add("html", "text/html;charset=utf-8");
|
||||
// CloudFoundry issue, see https://github.com/cloudfoundry/gorouter/issues/64
|
||||
mappings.add("json", "text/html;charset=utf-8");
|
||||
container.setMimeMappings(mappings);
|
||||
// When running in an IDE or with ./mvnw spring-boot:run, set location of the static web assets.
|
||||
setLocationForStaticAssets(container);
|
||||
|
||||
/*
|
||||
* Enable HTTP/2 for Undertow - https://twitter.com/ankinson/status/829256167700492288
|
||||
* HTTP/2 requires HTTPS, so HTTP requests will fallback to HTTP/1.1.
|
||||
* See the JHipsterProperties class and your application-*.yml configuration files
|
||||
* for more information.
|
||||
*/
|
||||
if (jHipsterProperties.getHttp().getVersion().equals(JHipsterProperties.Http.Version.V_2_0) &&
|
||||
container instanceof UndertowEmbeddedServletContainerFactory) {
|
||||
|
||||
((UndertowEmbeddedServletContainerFactory) container)
|
||||
.addBuilderCustomizers(builder ->
|
||||
builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true));
|
||||
}
|
||||
}
|
||||
|
||||
private void setLocationForStaticAssets(ConfigurableEmbeddedServletContainer container) {
|
||||
File root;
|
||||
String prefixPath = resolvePathPrefix();
|
||||
root = new File(prefixPath + "target/www/");
|
||||
if (root.exists() && root.isDirectory()) {
|
||||
container.setDocumentRoot(root);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve path prefix to static resources.
|
||||
*/
|
||||
private String resolvePathPrefix() {
|
||||
String fullExecutablePath = this.getClass().getResource("").getPath();
|
||||
String rootPath = Paths.get(".").toUri().normalize().getPath();
|
||||
String extractedPath = fullExecutablePath.replace(rootPath, "");
|
||||
int extractionEndIndex = extractedPath.indexOf("target/");
|
||||
if(extractionEndIndex <= 0) {
|
||||
return "";
|
||||
}
|
||||
return extractedPath.substring(0, extractionEndIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the caching HTTP Headers Filter.
|
||||
*/
|
||||
private void initCachingHttpHeadersFilter(ServletContext servletContext,
|
||||
EnumSet<DispatcherType> disps) {
|
||||
log.debug("Registering Caching HTTP Headers Filter");
|
||||
FilterRegistration.Dynamic cachingHttpHeadersFilter =
|
||||
servletContext.addFilter("cachingHttpHeadersFilter",
|
||||
new CachingHttpHeadersFilter(jHipsterProperties));
|
||||
|
||||
cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/content/*");
|
||||
cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/app/*");
|
||||
cachingHttpHeadersFilter.setAsyncSupported(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes Metrics.
|
||||
*/
|
||||
private void initMetrics(ServletContext servletContext, EnumSet<DispatcherType> disps) {
|
||||
log.debug("Initializing Metrics registries");
|
||||
servletContext.setAttribute(InstrumentedFilter.REGISTRY_ATTRIBUTE,
|
||||
metricRegistry);
|
||||
servletContext.setAttribute(MetricsServlet.METRICS_REGISTRY,
|
||||
metricRegistry);
|
||||
|
||||
log.debug("Registering Metrics Filter");
|
||||
FilterRegistration.Dynamic metricsFilter = servletContext.addFilter("webappMetricsFilter",
|
||||
new InstrumentedFilter());
|
||||
|
||||
metricsFilter.addMappingForUrlPatterns(disps, true, "/*");
|
||||
metricsFilter.setAsyncSupported(true);
|
||||
|
||||
log.debug("Registering Metrics Servlet");
|
||||
ServletRegistration.Dynamic metricsAdminServlet =
|
||||
servletContext.addServlet("metricsServlet", new MetricsServlet());
|
||||
|
||||
metricsAdminServlet.addMapping("/management/metrics/*");
|
||||
metricsAdminServlet.setAsyncSupported(true);
|
||||
metricsAdminServlet.setLoadOnStartup(2);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
CorsConfiguration config = jHipsterProperties.getCors();
|
||||
if (config.getAllowedOrigins() != null && !config.getAllowedOrigins().isEmpty()) {
|
||||
log.debug("Registering CORS filter");
|
||||
source.registerCorsConfiguration("/api/**", config);
|
||||
source.registerCorsConfiguration("/v2/api-docs", config);
|
||||
}
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes H2 console.
|
||||
*/
|
||||
private void initH2Console(ServletContext servletContext) {
|
||||
log.debug("Initialize H2 console");
|
||||
ServletRegistration.Dynamic h2ConsoleServlet = servletContext.addServlet("H2Console", new org.h2.server.web.WebServlet());
|
||||
h2ConsoleServlet.addMapping("/h2-console/*");
|
||||
h2ConsoleServlet.setInitParameter("-properties", "src/main/resources/");
|
||||
h2ConsoleServlet.setLoadOnStartup(1);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setMetricRegistry(MetricRegistry metricRegistry) {
|
||||
this.metricRegistry = metricRegistry;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package com.baeldung.config.audit;
|
||||
|
||||
import com.baeldung.domain.PersistentAuditEvent;
|
||||
|
||||
import org.springframework.boot.actuate.audit.AuditEvent;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetails;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.util.*;
|
||||
|
||||
@Component
|
||||
public class AuditEventConverter {
|
||||
|
||||
/**
|
||||
* Convert a list of PersistentAuditEvent to a list of AuditEvent
|
||||
*
|
||||
* @param persistentAuditEvents the list to convert
|
||||
* @return the converted list.
|
||||
*/
|
||||
public List<AuditEvent> convertToAuditEvent(Iterable<PersistentAuditEvent> persistentAuditEvents) {
|
||||
if (persistentAuditEvents == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<AuditEvent> auditEvents = new ArrayList<>();
|
||||
for (PersistentAuditEvent persistentAuditEvent : persistentAuditEvents) {
|
||||
auditEvents.add(convertToAuditEvent(persistentAuditEvent));
|
||||
}
|
||||
return auditEvents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a PersistentAuditEvent to an AuditEvent
|
||||
*
|
||||
* @param persistentAuditEvent the event to convert
|
||||
* @return the converted list.
|
||||
*/
|
||||
public AuditEvent convertToAuditEvent(PersistentAuditEvent persistentAuditEvent) {
|
||||
Instant instant = persistentAuditEvent.getAuditEventDate().atZone(ZoneId.systemDefault()).toInstant();
|
||||
return new AuditEvent(Date.from(instant), persistentAuditEvent.getPrincipal(),
|
||||
persistentAuditEvent.getAuditEventType(), convertDataToObjects(persistentAuditEvent.getData()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal conversion. This is needed to support the current SpringBoot actuator AuditEventRepository interface
|
||||
*
|
||||
* @param data the data to convert
|
||||
* @return a map of String, Object
|
||||
*/
|
||||
public Map<String, Object> convertDataToObjects(Map<String, String> data) {
|
||||
Map<String, Object> results = new HashMap<>();
|
||||
|
||||
if (data != null) {
|
||||
for (Map.Entry<String, String> entry : data.entrySet()) {
|
||||
results.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal conversion. This method will allow to save additional data.
|
||||
* By default, it will save the object as string
|
||||
*
|
||||
* @param data the data to convert
|
||||
* @return a map of String, String
|
||||
*/
|
||||
public Map<String, String> convertDataToStrings(Map<String, Object> data) {
|
||||
Map<String, String> results = new HashMap<>();
|
||||
|
||||
if (data != null) {
|
||||
for (Map.Entry<String, Object> entry : data.entrySet()) {
|
||||
Object object = entry.getValue();
|
||||
|
||||
// Extract the data that will be saved.
|
||||
if (object instanceof WebAuthenticationDetails) {
|
||||
WebAuthenticationDetails authenticationDetails = (WebAuthenticationDetails) object;
|
||||
results.put("remoteAddress", authenticationDetails.getRemoteAddress());
|
||||
results.put("sessionId", authenticationDetails.getSessionId());
|
||||
} else if (object != null) {
|
||||
results.put(entry.getKey(), object.toString());
|
||||
} else {
|
||||
results.put(entry.getKey(), "null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Audit specific code.
|
||||
*/
|
||||
package com.baeldung.config.audit;
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Spring Framework configuration files.
|
||||
*/
|
||||
package com.baeldung.config;
|
|
@ -0,0 +1,80 @@
|
|||
package com.baeldung.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.hibernate.envers.Audited;
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
import java.time.ZonedDateTime;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.EntityListeners;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
/**
|
||||
* Base abstract class for entities which will hold definitions for created, last modified by and created,
|
||||
* last modified by date.
|
||||
*/
|
||||
@MappedSuperclass
|
||||
@Audited
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public abstract class AbstractAuditingEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@CreatedBy
|
||||
@Column(name = "created_by", nullable = false, length = 50, updatable = false)
|
||||
@JsonIgnore
|
||||
private String createdBy;
|
||||
|
||||
@CreatedDate
|
||||
@Column(name = "created_date", nullable = false)
|
||||
@JsonIgnore
|
||||
private ZonedDateTime createdDate = ZonedDateTime.now();
|
||||
|
||||
@LastModifiedBy
|
||||
@Column(name = "last_modified_by", length = 50)
|
||||
@JsonIgnore
|
||||
private String lastModifiedBy;
|
||||
|
||||
@LastModifiedDate
|
||||
@Column(name = "last_modified_date")
|
||||
@JsonIgnore
|
||||
private ZonedDateTime lastModifiedDate = ZonedDateTime.now();
|
||||
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
|
||||
public void setCreatedBy(String createdBy) {
|
||||
this.createdBy = createdBy;
|
||||
}
|
||||
|
||||
public ZonedDateTime getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
public void setCreatedDate(ZonedDateTime createdDate) {
|
||||
this.createdDate = createdDate;
|
||||
}
|
||||
|
||||
public String getLastModifiedBy() {
|
||||
return lastModifiedBy;
|
||||
}
|
||||
|
||||
public void setLastModifiedBy(String lastModifiedBy) {
|
||||
this.lastModifiedBy = lastModifiedBy;
|
||||
}
|
||||
|
||||
public ZonedDateTime getLastModifiedDate() {
|
||||
return lastModifiedDate;
|
||||
}
|
||||
|
||||
public void setLastModifiedDate(ZonedDateTime lastModifiedDate) {
|
||||
this.lastModifiedDate = lastModifiedDate;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package com.baeldung.domain;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Column;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An authority (a security role) used by Spring Security.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "jhi_authority")
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||
public class Authority implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 0, max = 50)
|
||||
@Id
|
||||
@Column(length = 50)
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Authority authority = (Authority) o;
|
||||
|
||||
if (name != null ? !name.equals(authority.name) : authority.name != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name != null ? name.hashCode() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Authority{" +
|
||||
"name='" + name + '\'' +
|
||||
"}";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
package com.baeldung.domain;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A Comment.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "comment")
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||
public class Comment implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 10, max = 100)
|
||||
@Column(name = "text", length = 100, nullable = false)
|
||||
private String text;
|
||||
|
||||
@NotNull
|
||||
@Column(name = "creation_date", nullable = false)
|
||||
private LocalDate creationDate;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@NotNull
|
||||
private Post post;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public Comment text(String text) {
|
||||
this.text = text;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public LocalDate getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
public Comment creationDate(LocalDate creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setCreationDate(LocalDate creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
public Post getPost() {
|
||||
return post;
|
||||
}
|
||||
|
||||
public Comment post(Post post) {
|
||||
this.post = post;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setPost(Post post) {
|
||||
this.post = post;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Comment comment = (Comment) o;
|
||||
if (comment.id == null || id == null) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(id, comment.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Comment{" +
|
||||
"id=" + id +
|
||||
", text='" + text + "'" +
|
||||
", creationDate='" + creationDate + "'" +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package com.baeldung.domain;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Persist AuditEvent managed by the Spring Boot actuator
|
||||
* @see org.springframework.boot.actuate.audit.AuditEvent
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "jhi_persistent_audit_event")
|
||||
public class PersistentAuditEvent implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "event_id")
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
@Column(nullable = false)
|
||||
private String principal;
|
||||
|
||||
@Column(name = "event_date")
|
||||
private LocalDateTime auditEventDate;
|
||||
@Column(name = "event_type")
|
||||
private String auditEventType;
|
||||
|
||||
@ElementCollection
|
||||
@MapKeyColumn(name = "name")
|
||||
@Column(name = "value")
|
||||
@CollectionTable(name = "jhi_persistent_audit_evt_data", joinColumns=@JoinColumn(name="event_id"))
|
||||
private Map<String, String> data = new HashMap<>();
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
|
||||
public void setPrincipal(String principal) {
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
public LocalDateTime getAuditEventDate() {
|
||||
return auditEventDate;
|
||||
}
|
||||
|
||||
public void setAuditEventDate(LocalDateTime auditEventDate) {
|
||||
this.auditEventDate = auditEventDate;
|
||||
}
|
||||
|
||||
public String getAuditEventType() {
|
||||
return auditEventType;
|
||||
}
|
||||
|
||||
public void setAuditEventType(String auditEventType) {
|
||||
this.auditEventType = auditEventType;
|
||||
}
|
||||
|
||||
public Map<String, String> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(Map<String, String> data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
package com.baeldung.domain;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A Post.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "post")
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||
public class Post implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 10, max = 100)
|
||||
@Column(name = "title", length = 100, nullable = false)
|
||||
private String title;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 10, max = 1000)
|
||||
@Column(name = "content", length = 1000, nullable = false)
|
||||
private String content;
|
||||
|
||||
@NotNull
|
||||
@Column(name = "creation_date", nullable = false)
|
||||
private LocalDate creationDate;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@NotNull
|
||||
private User creator;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public Post title(String title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public Post content(String content) {
|
||||
this.content = content;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public LocalDate getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
public Post creationDate(LocalDate creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setCreationDate(LocalDate creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
public User getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
public Post creator(User user) {
|
||||
this.creator = user;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setCreator(User user) {
|
||||
this.creator = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Post post = (Post) o;
|
||||
if (post.id == null || id == null) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(id, post.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Post{" +
|
||||
"id=" + id +
|
||||
", title='" + title + "'" +
|
||||
", content='" + content + "'" +
|
||||
", creationDate='" + creationDate + "'" +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
package com.baeldung.domain;
|
||||
|
||||
import com.baeldung.config.Constants;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.hibernate.annotations.BatchSize;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.validator.constraints.Email;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
/**
|
||||
* A user.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "jhi_user")
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||
public class User extends AbstractAuditingEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
@Pattern(regexp = Constants.LOGIN_REGEX)
|
||||
@Size(min = 1, max = 50)
|
||||
@Column(length = 50, unique = true, nullable = false)
|
||||
private String login;
|
||||
|
||||
@JsonIgnore
|
||||
@NotNull
|
||||
@Size(min = 60, max = 60)
|
||||
@Column(name = "password_hash",length = 60)
|
||||
private String password;
|
||||
|
||||
@Size(max = 50)
|
||||
@Column(name = "first_name", length = 50)
|
||||
private String firstName;
|
||||
|
||||
@Size(max = 50)
|
||||
@Column(name = "last_name", length = 50)
|
||||
private String lastName;
|
||||
|
||||
@Email
|
||||
@Size(max = 100)
|
||||
@Column(length = 100, unique = true)
|
||||
private String email;
|
||||
|
||||
@NotNull
|
||||
@Column(nullable = false)
|
||||
private boolean activated = false;
|
||||
|
||||
@Size(min = 2, max = 5)
|
||||
@Column(name = "lang_key", length = 5)
|
||||
private String langKey;
|
||||
|
||||
@Size(max = 256)
|
||||
@Column(name = "image_url", length = 256)
|
||||
private String imageUrl;
|
||||
|
||||
@Size(max = 20)
|
||||
@Column(name = "activation_key", length = 20)
|
||||
@JsonIgnore
|
||||
private String activationKey;
|
||||
|
||||
@Size(max = 20)
|
||||
@Column(name = "reset_key", length = 20)
|
||||
private String resetKey;
|
||||
|
||||
@Column(name = "reset_date")
|
||||
private ZonedDateTime resetDate = null;
|
||||
|
||||
@JsonIgnore
|
||||
@ManyToMany
|
||||
@JoinTable(
|
||||
name = "jhi_user_authority",
|
||||
joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
|
||||
inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "name")})
|
||||
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||
@BatchSize(size = 20)
|
||||
private Set<Authority> authorities = new HashSet<>();
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
//Lowercase the login before saving it in database
|
||||
public void setLogin(String login) {
|
||||
this.login = login.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getImageUrl() {
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
public void setImageUrl(String imageUrl) {
|
||||
this.imageUrl = imageUrl;
|
||||
}
|
||||
|
||||
public boolean getActivated() {
|
||||
return activated;
|
||||
}
|
||||
|
||||
public void setActivated(boolean activated) {
|
||||
this.activated = activated;
|
||||
}
|
||||
|
||||
public String getActivationKey() {
|
||||
return activationKey;
|
||||
}
|
||||
|
||||
public void setActivationKey(String activationKey) {
|
||||
this.activationKey = activationKey;
|
||||
}
|
||||
|
||||
public String getResetKey() {
|
||||
return resetKey;
|
||||
}
|
||||
|
||||
public void setResetKey(String resetKey) {
|
||||
this.resetKey = resetKey;
|
||||
}
|
||||
|
||||
public ZonedDateTime getResetDate() {
|
||||
return resetDate;
|
||||
}
|
||||
|
||||
public void setResetDate(ZonedDateTime resetDate) {
|
||||
this.resetDate = resetDate;
|
||||
}
|
||||
|
||||
public String getLangKey() {
|
||||
return langKey;
|
||||
}
|
||||
|
||||
public void setLangKey(String langKey) {
|
||||
this.langKey = langKey;
|
||||
}
|
||||
|
||||
public Set<Authority> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
public void setAuthorities(Set<Authority> authorities) {
|
||||
this.authorities = authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
User user = (User) o;
|
||||
|
||||
if (!login.equals(user.login)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return login.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User{" +
|
||||
"login='" + login + '\'' +
|
||||
", firstName='" + firstName + '\'' +
|
||||
", lastName='" + lastName + '\'' +
|
||||
", email='" + email + '\'' +
|
||||
", imageUrl='" + imageUrl + '\'' +
|
||||
", activated='" + activated + '\'' +
|
||||
", langKey='" + langKey + '\'' +
|
||||
", activationKey='" + activationKey + '\'' +
|
||||
"}";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* JPA domain objects.
|
||||
*/
|
||||
package com.baeldung.domain;
|
|
@ -0,0 +1,11 @@
|
|||
package com.baeldung.repository;
|
||||
|
||||
import com.baeldung.domain.Authority;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
/**
|
||||
* Spring Data JPA repository for the Authority entity.
|
||||
*/
|
||||
public interface AuthorityRepository extends JpaRepository<Authority, String> {
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.repository;
|
||||
|
||||
import com.baeldung.domain.Comment;
|
||||
|
||||
import org.springframework.data.jpa.repository.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Spring Data JPA repository for the Comment entity.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public interface CommentRepository extends JpaRepository<Comment,Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package com.baeldung.repository;
|
||||
|
||||
import com.baeldung.config.Constants;
|
||||
import com.baeldung.config.audit.AuditEventConverter;
|
||||
import com.baeldung.domain.PersistentAuditEvent;
|
||||
|
||||
import org.springframework.boot.actuate.audit.AuditEvent;
|
||||
import org.springframework.boot.actuate.audit.AuditEventRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An implementation of Spring Boot's AuditEventRepository.
|
||||
*/
|
||||
@Repository
|
||||
public class CustomAuditEventRepository implements AuditEventRepository {
|
||||
|
||||
private static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE";
|
||||
|
||||
private final PersistenceAuditEventRepository persistenceAuditEventRepository;
|
||||
|
||||
private final AuditEventConverter auditEventConverter;
|
||||
|
||||
public CustomAuditEventRepository(PersistenceAuditEventRepository persistenceAuditEventRepository,
|
||||
AuditEventConverter auditEventConverter) {
|
||||
|
||||
this.persistenceAuditEventRepository = persistenceAuditEventRepository;
|
||||
this.auditEventConverter = auditEventConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuditEvent> find(Date after) {
|
||||
Iterable<PersistentAuditEvent> persistentAuditEvents =
|
||||
persistenceAuditEventRepository.findByAuditEventDateAfter(LocalDateTime.from(after.toInstant()));
|
||||
return auditEventConverter.convertToAuditEvent(persistentAuditEvents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuditEvent> find(String principal, Date after) {
|
||||
Iterable<PersistentAuditEvent> persistentAuditEvents;
|
||||
if (principal == null && after == null) {
|
||||
persistentAuditEvents = persistenceAuditEventRepository.findAll();
|
||||
} else if (after == null) {
|
||||
persistentAuditEvents = persistenceAuditEventRepository.findByPrincipal(principal);
|
||||
} else {
|
||||
persistentAuditEvents =
|
||||
persistenceAuditEventRepository.findByPrincipalAndAuditEventDateAfter(principal, LocalDateTime.from(after.toInstant()));
|
||||
}
|
||||
return auditEventConverter.convertToAuditEvent(persistentAuditEvents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuditEvent> find(String principal, Date after, String type) {
|
||||
Iterable<PersistentAuditEvent> persistentAuditEvents =
|
||||
persistenceAuditEventRepository.findByPrincipalAndAuditEventDateAfterAndAuditEventType(principal, LocalDateTime.from(after.toInstant()), type);
|
||||
return auditEventConverter.convertToAuditEvent(persistentAuditEvents);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public void add(AuditEvent event) {
|
||||
if (!AUTHORIZATION_FAILURE.equals(event.getType()) &&
|
||||
!Constants.ANONYMOUS_USER.equals(event.getPrincipal())) {
|
||||
|
||||
PersistentAuditEvent persistentAuditEvent = new PersistentAuditEvent();
|
||||
persistentAuditEvent.setPrincipal(event.getPrincipal());
|
||||
persistentAuditEvent.setAuditEventType(event.getType());
|
||||
Instant instant = Instant.ofEpochMilli(event.getTimestamp().getTime());
|
||||
persistentAuditEvent.setAuditEventDate(LocalDateTime.ofInstant(instant, ZoneId.systemDefault()));
|
||||
persistentAuditEvent.setData(auditEventConverter.convertDataToStrings(event.getData()));
|
||||
persistenceAuditEventRepository.save(persistentAuditEvent);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.repository;
|
||||
|
||||
import com.baeldung.domain.PersistentAuditEvent;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Spring Data JPA repository for the PersistentAuditEvent entity.
|
||||
*/
|
||||
public interface PersistenceAuditEventRepository extends JpaRepository<PersistentAuditEvent, Long> {
|
||||
|
||||
List<PersistentAuditEvent> findByPrincipal(String principal);
|
||||
|
||||
List<PersistentAuditEvent> findByAuditEventDateAfter(LocalDateTime after);
|
||||
|
||||
List<PersistentAuditEvent> findByPrincipalAndAuditEventDateAfter(String principal, LocalDateTime after);
|
||||
|
||||
List<PersistentAuditEvent> findByPrincipalAndAuditEventDateAfterAndAuditEventType(String principle, LocalDateTime after, String type);
|
||||
|
||||
Page<PersistentAuditEvent> findAllByAuditEventDateBetween(LocalDateTime fromDate, LocalDateTime toDate, Pageable pageable);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.baeldung.repository;
|
||||
|
||||
import com.baeldung.domain.Post;
|
||||
|
||||
import org.springframework.data.jpa.repository.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Spring Data JPA repository for the Post entity.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public interface PostRepository extends JpaRepository<Post,Long> {
|
||||
|
||||
@Query("select post from Post post where post.creator.login = ?#{principal.username}")
|
||||
List<Post> findByCreatorIsCurrentUser();
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.baeldung.repository;
|
||||
|
||||
import com.baeldung.domain.User;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Spring Data JPA repository for the User entity.
|
||||
*/
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
|
||||
Optional<User> findOneByActivationKey(String activationKey);
|
||||
|
||||
List<User> findAllByActivatedIsFalseAndCreatedDateBefore(ZonedDateTime dateTime);
|
||||
|
||||
Optional<User> findOneByResetKey(String resetKey);
|
||||
|
||||
Optional<User> findOneByEmail(String email);
|
||||
|
||||
Optional<User> findOneByLogin(String login);
|
||||
|
||||
@EntityGraph(attributePaths = "authorities")
|
||||
User findOneWithAuthoritiesById(Long id);
|
||||
|
||||
@EntityGraph(attributePaths = "authorities")
|
||||
Optional<User> findOneWithAuthoritiesByLogin(String login);
|
||||
|
||||
Page<User> findAllByLoginNot(Pageable pageable, String login);
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Spring Data JPA repositories.
|
||||
*/
|
||||
package com.baeldung.repository;
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.security;
|
||||
|
||||
/**
|
||||
* Constants for Spring Security authorities.
|
||||
*/
|
||||
public final class AuthoritiesConstants {
|
||||
|
||||
public static final String ADMIN = "ROLE_ADMIN";
|
||||
|
||||
public static final String USER = "ROLE_USER";
|
||||
|
||||
public static final String ANONYMOUS = "ROLE_ANONYMOUS";
|
||||
|
||||
private AuthoritiesConstants() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.baeldung.security;
|
||||
|
||||
import com.baeldung.domain.User;
|
||||
import com.baeldung.repository.UserRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Authenticate a user from the database.
|
||||
*/
|
||||
@Component("userDetailsService")
|
||||
public class DomainUserDetailsService implements UserDetailsService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class);
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public DomainUserDetailsService(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public UserDetails loadUserByUsername(final String login) {
|
||||
log.debug("Authenticating {}", login);
|
||||
String lowercaseLogin = login.toLowerCase(Locale.ENGLISH);
|
||||
Optional<User> userFromDatabase = userRepository.findOneWithAuthoritiesByLogin(lowercaseLogin);
|
||||
return userFromDatabase.map(user -> {
|
||||
if (!user.getActivated()) {
|
||||
throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated");
|
||||
}
|
||||
List<GrantedAuthority> grantedAuthorities = user.getAuthorities().stream()
|
||||
.map(authority -> new SimpleGrantedAuthority(authority.getName()))
|
||||
.collect(Collectors.toList());
|
||||
return new org.springframework.security.core.userdetails.User(lowercaseLogin,
|
||||
user.getPassword(),
|
||||
grantedAuthorities);
|
||||
}).orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the " +
|
||||
"database"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package com.baeldung.security;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
/**
|
||||
* Utility class for Spring Security.
|
||||
*/
|
||||
public final class SecurityUtils {
|
||||
|
||||
private SecurityUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the login of the current user.
|
||||
*
|
||||
* @return the login of the current user
|
||||
*/
|
||||
public static String getCurrentUserLogin() {
|
||||
SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
Authentication authentication = securityContext.getAuthentication();
|
||||
String userName = null;
|
||||
if (authentication != null) {
|
||||
if (authentication.getPrincipal() instanceof UserDetails) {
|
||||
UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
|
||||
userName = springSecurityUser.getUsername();
|
||||
} else if (authentication.getPrincipal() instanceof String) {
|
||||
userName = (String) authentication.getPrincipal();
|
||||
}
|
||||
}
|
||||
return userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user is authenticated.
|
||||
*
|
||||
* @return true if the user is authenticated, false otherwise
|
||||
*/
|
||||
public static boolean isAuthenticated() {
|
||||
SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
Authentication authentication = securityContext.getAuthentication();
|
||||
if (authentication != null) {
|
||||
return authentication.getAuthorities().stream()
|
||||
.noneMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(AuthoritiesConstants.ANONYMOUS));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current user has a specific authority (security role).
|
||||
*
|
||||
* <p>The name of this method comes from the isUserInRole() method in the Servlet API</p>
|
||||
*
|
||||
* @param authority the authority to check
|
||||
* @return true if the current user has the authority, false otherwise
|
||||
*/
|
||||
public static boolean isCurrentUserInRole(String authority) {
|
||||
SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
Authentication authentication = securityContext.getAuthentication();
|
||||
if (authentication != null) {
|
||||
return authentication.getAuthorities().stream()
|
||||
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(authority));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.baeldung.security;
|
||||
|
||||
import com.baeldung.config.Constants;
|
||||
|
||||
import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Implementation of AuditorAware based on Spring Security.
|
||||
*/
|
||||
@Component
|
||||
public class SpringSecurityAuditorAware implements AuditorAware<String> {
|
||||
|
||||
@Override
|
||||
public String getCurrentAuditor() {
|
||||
String userName = SecurityUtils.getCurrentUserLogin();
|
||||
return userName != null ? userName : Constants.SYSTEM_ACCOUNT;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.baeldung.security;
|
||||
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
|
||||
/**
|
||||
* This exception is thrown in case of a not activated user trying to authenticate.
|
||||
*/
|
||||
public class UserNotActivatedException extends AuthenticationException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UserNotActivatedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UserNotActivatedException(String message, Throwable t) {
|
||||
super(message, t);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.security.jwt;
|
||||
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
public class JWTConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
|
||||
|
||||
public static final String AUTHORIZATION_HEADER = "Authorization";
|
||||
|
||||
private TokenProvider tokenProvider;
|
||||
|
||||
public JWTConfigurer(TokenProvider tokenProvider) {
|
||||
this.tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(HttpSecurity http) throws Exception {
|
||||
JWTFilter customFilter = new JWTFilter(tokenProvider);
|
||||
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.baeldung.security.jwt;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.GenericFilterBean;
|
||||
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
|
||||
/**
|
||||
* Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is
|
||||
* found.
|
||||
*/
|
||||
public class JWTFilter extends GenericFilterBean {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(JWTFilter.class);
|
||||
|
||||
private TokenProvider tokenProvider;
|
||||
|
||||
public JWTFilter(TokenProvider tokenProvider) {
|
||||
this.tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
|
||||
throws IOException, ServletException {
|
||||
try {
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
|
||||
String jwt = resolveToken(httpServletRequest);
|
||||
if (StringUtils.hasText(jwt) && this.tokenProvider.validateToken(jwt)) {
|
||||
Authentication authentication = this.tokenProvider.getAuthentication(jwt);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
} catch (ExpiredJwtException eje) {
|
||||
log.info("Security exception for user {} - {}",
|
||||
eje.getClaims().getSubject(), eje.getMessage());
|
||||
|
||||
log.trace("Security exception trace: {}", eje);
|
||||
((HttpServletResponse) servletResponse).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveToken(HttpServletRequest request){
|
||||
String bearerToken = request.getHeader(JWTConfigurer.AUTHORIZATION_HEADER);
|
||||
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
|
||||
return bearerToken.substring(7, bearerToken.length());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package com.baeldung.security.jwt;
|
||||
|
||||
import io.github.jhipster.config.JHipsterProperties;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import io.jsonwebtoken.*;
|
||||
|
||||
@Component
|
||||
public class TokenProvider {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(TokenProvider.class);
|
||||
|
||||
private static final String AUTHORITIES_KEY = "auth";
|
||||
|
||||
private String secretKey;
|
||||
|
||||
private long tokenValidityInMilliseconds;
|
||||
|
||||
private long tokenValidityInMillisecondsForRememberMe;
|
||||
|
||||
private final JHipsterProperties jHipsterProperties;
|
||||
|
||||
public TokenProvider(JHipsterProperties jHipsterProperties) {
|
||||
this.jHipsterProperties = jHipsterProperties;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.secretKey =
|
||||
jHipsterProperties.getSecurity().getAuthentication().getJwt().getSecret();
|
||||
|
||||
this.tokenValidityInMilliseconds =
|
||||
1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSeconds();
|
||||
this.tokenValidityInMillisecondsForRememberMe =
|
||||
1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSecondsForRememberMe();
|
||||
}
|
||||
|
||||
public String createToken(Authentication authentication, Boolean rememberMe) {
|
||||
String authorities = authentication.getAuthorities().stream()
|
||||
.map(GrantedAuthority::getAuthority)
|
||||
.collect(Collectors.joining(","));
|
||||
|
||||
long now = (new Date()).getTime();
|
||||
Date validity;
|
||||
if (rememberMe) {
|
||||
validity = new Date(now + this.tokenValidityInMillisecondsForRememberMe);
|
||||
} else {
|
||||
validity = new Date(now + this.tokenValidityInMilliseconds);
|
||||
}
|
||||
|
||||
return Jwts.builder()
|
||||
.setSubject(authentication.getName())
|
||||
.claim(AUTHORITIES_KEY, authorities)
|
||||
.signWith(SignatureAlgorithm.HS512, secretKey)
|
||||
.setExpiration(validity)
|
||||
.compact();
|
||||
}
|
||||
|
||||
public Authentication getAuthentication(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(secretKey)
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
Collection<? extends GrantedAuthority> authorities =
|
||||
Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
|
||||
.map(SimpleGrantedAuthority::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
User principal = new User(claims.getSubject(), "", authorities);
|
||||
|
||||
return new UsernamePasswordAuthenticationToken(principal, "", authorities);
|
||||
}
|
||||
|
||||
public boolean validateToken(String authToken) {
|
||||
try {
|
||||
Jwts.parser().setSigningKey(secretKey).parseClaimsJws(authToken);
|
||||
return true;
|
||||
} catch (SignatureException e) {
|
||||
log.info("Invalid JWT signature.");
|
||||
log.trace("Invalid JWT signature trace: {}", e);
|
||||
} catch (MalformedJwtException e) {
|
||||
log.info("Invalid JWT token.");
|
||||
log.trace("Invalid JWT token trace: {}", e);
|
||||
} catch (ExpiredJwtException e) {
|
||||
log.info("Expired JWT token.");
|
||||
log.trace("Expired JWT token trace: {}", e);
|
||||
} catch (UnsupportedJwtException e) {
|
||||
log.info("Unsupported JWT token.");
|
||||
log.trace("Unsupported JWT token trace: {}", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.info("JWT token compact of handler are invalid.");
|
||||
log.trace("JWT token compact of handler are invalid trace: {}", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Spring Security configuration.
|
||||
*/
|
||||
package com.baeldung.security;
|
|
@ -0,0 +1,50 @@
|
|||
package com.baeldung.service;
|
||||
|
||||
import com.baeldung.config.audit.AuditEventConverter;
|
||||
import com.baeldung.repository.PersistenceAuditEventRepository;
|
||||
import java.time.LocalDateTime;
|
||||
import org.springframework.boot.actuate.audit.AuditEvent;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Service for managing audit events.
|
||||
* <p>
|
||||
* This is the default implementation to support SpringBoot Actuator AuditEventRepository
|
||||
* </p>
|
||||
*/
|
||||
@Service
|
||||
@Transactional
|
||||
public class AuditEventService {
|
||||
|
||||
private final PersistenceAuditEventRepository persistenceAuditEventRepository;
|
||||
|
||||
private final AuditEventConverter auditEventConverter;
|
||||
|
||||
public AuditEventService(
|
||||
PersistenceAuditEventRepository persistenceAuditEventRepository,
|
||||
AuditEventConverter auditEventConverter) {
|
||||
|
||||
this.persistenceAuditEventRepository = persistenceAuditEventRepository;
|
||||
this.auditEventConverter = auditEventConverter;
|
||||
}
|
||||
|
||||
public Page<AuditEvent> findAll(Pageable pageable) {
|
||||
return persistenceAuditEventRepository.findAll(pageable)
|
||||
.map(auditEventConverter::convertToAuditEvent);
|
||||
}
|
||||
|
||||
public Page<AuditEvent> findByDates(LocalDateTime fromDate, LocalDateTime toDate, Pageable pageable) {
|
||||
return persistenceAuditEventRepository.findAllByAuditEventDateBetween(fromDate, toDate, pageable)
|
||||
.map(auditEventConverter::convertToAuditEvent);
|
||||
}
|
||||
|
||||
public Optional<AuditEvent> find(Long id) {
|
||||
return Optional.ofNullable(persistenceAuditEventRepository.findOne(id)).map
|
||||
(auditEventConverter::convertToAuditEvent);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package com.baeldung.service;
|
||||
|
||||
import com.baeldung.domain.User;
|
||||
|
||||
import io.github.jhipster.config.JHipsterProperties;
|
||||
|
||||
import org.apache.commons.lang3.CharEncoding;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thymeleaf.context.Context;
|
||||
import org.thymeleaf.spring4.SpringTemplateEngine;
|
||||
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Service for sending e-mails.
|
||||
* <p>
|
||||
* We use the @Async annotation to send e-mails asynchronously.
|
||||
* </p>
|
||||
*/
|
||||
@Service
|
||||
public class MailService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MailService.class);
|
||||
|
||||
private static final String USER = "user";
|
||||
|
||||
private static final String BASE_URL = "baseUrl";
|
||||
|
||||
private final JHipsterProperties jHipsterProperties;
|
||||
|
||||
private final JavaMailSender javaMailSender;
|
||||
|
||||
private final MessageSource messageSource;
|
||||
|
||||
private final SpringTemplateEngine templateEngine;
|
||||
|
||||
public MailService(JHipsterProperties jHipsterProperties, JavaMailSender javaMailSender,
|
||||
MessageSource messageSource, SpringTemplateEngine templateEngine) {
|
||||
|
||||
this.jHipsterProperties = jHipsterProperties;
|
||||
this.javaMailSender = javaMailSender;
|
||||
this.messageSource = messageSource;
|
||||
this.templateEngine = templateEngine;
|
||||
}
|
||||
|
||||
@Async
|
||||
public void sendEmail(String to, String subject, String content, boolean isMultipart, boolean isHtml) {
|
||||
log.debug("Send e-mail[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}",
|
||||
isMultipart, isHtml, to, subject, content);
|
||||
|
||||
// Prepare message using a Spring helper
|
||||
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
|
||||
try {
|
||||
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, CharEncoding.UTF_8);
|
||||
message.setTo(to);
|
||||
message.setFrom(jHipsterProperties.getMail().getFrom());
|
||||
message.setSubject(subject);
|
||||
message.setText(content, isHtml);
|
||||
javaMailSender.send(mimeMessage);
|
||||
log.debug("Sent e-mail to User '{}'", to);
|
||||
} catch (Exception e) {
|
||||
log.warn("E-mail could not be sent to user '{}'", to, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Async
|
||||
public void sendActivationEmail(User user) {
|
||||
log.debug("Sending activation e-mail to '{}'", user.getEmail());
|
||||
Locale locale = Locale.forLanguageTag(user.getLangKey());
|
||||
Context context = new Context(locale);
|
||||
context.setVariable(USER, user);
|
||||
context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl());
|
||||
String content = templateEngine.process("activationEmail", context);
|
||||
String subject = messageSource.getMessage("email.activation.title", null, locale);
|
||||
sendEmail(user.getEmail(), subject, content, false, true);
|
||||
}
|
||||
|
||||
@Async
|
||||
public void sendCreationEmail(User user) {
|
||||
log.debug("Sending creation e-mail to '{}'", user.getEmail());
|
||||
Locale locale = Locale.forLanguageTag(user.getLangKey());
|
||||
Context context = new Context(locale);
|
||||
context.setVariable(USER, user);
|
||||
context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl());
|
||||
String content = templateEngine.process("creationEmail", context);
|
||||
String subject = messageSource.getMessage("email.activation.title", null, locale);
|
||||
sendEmail(user.getEmail(), subject, content, false, true);
|
||||
}
|
||||
|
||||
@Async
|
||||
public void sendPasswordResetMail(User user) {
|
||||
log.debug("Sending password reset e-mail to '{}'", user.getEmail());
|
||||
Locale locale = Locale.forLanguageTag(user.getLangKey());
|
||||
Context context = new Context(locale);
|
||||
context.setVariable(USER, user);
|
||||
context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl());
|
||||
String content = templateEngine.process("passwordResetEmail", context);
|
||||
String subject = messageSource.getMessage("email.reset.title", null, locale);
|
||||
sendEmail(user.getEmail(), subject, content, false, true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
package com.baeldung.service;
|
||||
|
||||
import com.baeldung.domain.Authority;
|
||||
import com.baeldung.domain.User;
|
||||
import com.baeldung.repository.AuthorityRepository;
|
||||
import com.baeldung.config.Constants;
|
||||
import com.baeldung.repository.UserRepository;
|
||||
import com.baeldung.security.AuthoritiesConstants;
|
||||
import com.baeldung.security.SecurityUtils;
|
||||
import com.baeldung.service.util.RandomUtil;
|
||||
import com.baeldung.service.dto.UserDTO;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Service class for managing users.
|
||||
*/
|
||||
@Service
|
||||
@Transactional
|
||||
public class UserService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(UserService.class);
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
private final AuthorityRepository authorityRepository;
|
||||
|
||||
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, AuthorityRepository authorityRepository) {
|
||||
this.userRepository = userRepository;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
this.authorityRepository = authorityRepository;
|
||||
}
|
||||
|
||||
public Optional<User> activateRegistration(String key) {
|
||||
log.debug("Activating user for activation key {}", key);
|
||||
return userRepository.findOneByActivationKey(key)
|
||||
.map(user -> {
|
||||
// activate given user for the registration key.
|
||||
user.setActivated(true);
|
||||
user.setActivationKey(null);
|
||||
log.debug("Activated user: {}", user);
|
||||
return user;
|
||||
});
|
||||
}
|
||||
|
||||
public Optional<User> completePasswordReset(String newPassword, String key) {
|
||||
log.debug("Reset user password for reset key {}", key);
|
||||
|
||||
return userRepository.findOneByResetKey(key)
|
||||
.filter(user -> {
|
||||
ZonedDateTime oneDayAgo = ZonedDateTime.now().minusHours(24);
|
||||
return user.getResetDate().isAfter(oneDayAgo);
|
||||
})
|
||||
.map(user -> {
|
||||
user.setPassword(passwordEncoder.encode(newPassword));
|
||||
user.setResetKey(null);
|
||||
user.setResetDate(null);
|
||||
return user;
|
||||
});
|
||||
}
|
||||
|
||||
public Optional<User> requestPasswordReset(String mail) {
|
||||
return userRepository.findOneByEmail(mail)
|
||||
.filter(User::getActivated)
|
||||
.map(user -> {
|
||||
user.setResetKey(RandomUtil.generateResetKey());
|
||||
user.setResetDate(ZonedDateTime.now());
|
||||
return user;
|
||||
});
|
||||
}
|
||||
|
||||
public User createUser(String login, String password, String firstName, String lastName, String email,
|
||||
String imageUrl, String langKey) {
|
||||
|
||||
User newUser = new User();
|
||||
Authority authority = authorityRepository.findOne(AuthoritiesConstants.USER);
|
||||
Set<Authority> authorities = new HashSet<>();
|
||||
String encryptedPassword = passwordEncoder.encode(password);
|
||||
newUser.setLogin(login);
|
||||
// new user gets initially a generated password
|
||||
newUser.setPassword(encryptedPassword);
|
||||
newUser.setFirstName(firstName);
|
||||
newUser.setLastName(lastName);
|
||||
newUser.setEmail(email);
|
||||
newUser.setImageUrl(imageUrl);
|
||||
newUser.setLangKey(langKey);
|
||||
// new user is not active
|
||||
newUser.setActivated(false);
|
||||
// new user gets registration key
|
||||
newUser.setActivationKey(RandomUtil.generateActivationKey());
|
||||
authorities.add(authority);
|
||||
newUser.setAuthorities(authorities);
|
||||
userRepository.save(newUser);
|
||||
log.debug("Created Information for User: {}", newUser);
|
||||
return newUser;
|
||||
}
|
||||
|
||||
public User createUser(UserDTO userDTO) {
|
||||
User user = new User();
|
||||
user.setLogin(userDTO.getLogin());
|
||||
user.setFirstName(userDTO.getFirstName());
|
||||
user.setLastName(userDTO.getLastName());
|
||||
user.setEmail(userDTO.getEmail());
|
||||
user.setImageUrl(userDTO.getImageUrl());
|
||||
if (userDTO.getLangKey() == null) {
|
||||
user.setLangKey("en"); // default language
|
||||
} else {
|
||||
user.setLangKey(userDTO.getLangKey());
|
||||
}
|
||||
if (userDTO.getAuthorities() != null) {
|
||||
Set<Authority> authorities = new HashSet<>();
|
||||
userDTO.getAuthorities().forEach(
|
||||
authority -> authorities.add(authorityRepository.findOne(authority))
|
||||
);
|
||||
user.setAuthorities(authorities);
|
||||
}
|
||||
String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword());
|
||||
user.setPassword(encryptedPassword);
|
||||
user.setResetKey(RandomUtil.generateResetKey());
|
||||
user.setResetDate(ZonedDateTime.now());
|
||||
user.setActivated(true);
|
||||
userRepository.save(user);
|
||||
log.debug("Created Information for User: {}", user);
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update basic information (first name, last name, email, language) for the current user.
|
||||
*/
|
||||
public void updateUser(String firstName, String lastName, String email, String langKey) {
|
||||
userRepository.findOneByLogin(SecurityUtils.getCurrentUserLogin()).ifPresent(user -> {
|
||||
user.setFirstName(firstName);
|
||||
user.setLastName(lastName);
|
||||
user.setEmail(email);
|
||||
user.setLangKey(langKey);
|
||||
log.debug("Changed Information for User: {}", user);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all information for a specific user, and return the modified user.
|
||||
*/
|
||||
public Optional<UserDTO> updateUser(UserDTO userDTO) {
|
||||
return Optional.of(userRepository
|
||||
.findOne(userDTO.getId()))
|
||||
.map(user -> {
|
||||
user.setLogin(userDTO.getLogin());
|
||||
user.setFirstName(userDTO.getFirstName());
|
||||
user.setLastName(userDTO.getLastName());
|
||||
user.setEmail(userDTO.getEmail());
|
||||
user.setImageUrl(userDTO.getImageUrl());
|
||||
user.setActivated(userDTO.isActivated());
|
||||
user.setLangKey(userDTO.getLangKey());
|
||||
Set<Authority> managedAuthorities = user.getAuthorities();
|
||||
managedAuthorities.clear();
|
||||
userDTO.getAuthorities().stream()
|
||||
.map(authorityRepository::findOne)
|
||||
.forEach(managedAuthorities::add);
|
||||
log.debug("Changed Information for User: {}", user);
|
||||
return user;
|
||||
})
|
||||
.map(UserDTO::new);
|
||||
}
|
||||
|
||||
public void deleteUser(String login) {
|
||||
userRepository.findOneByLogin(login).ifPresent(user -> {
|
||||
userRepository.delete(user);
|
||||
log.debug("Deleted User: {}", user);
|
||||
});
|
||||
}
|
||||
|
||||
public void changePassword(String password) {
|
||||
userRepository.findOneByLogin(SecurityUtils.getCurrentUserLogin()).ifPresent(user -> {
|
||||
String encryptedPassword = passwordEncoder.encode(password);
|
||||
user.setPassword(encryptedPassword);
|
||||
log.debug("Changed password for User: {}", user);
|
||||
});
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Page<UserDTO> getAllManagedUsers(Pageable pageable) {
|
||||
return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER).map(UserDTO::new);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Optional<User> getUserWithAuthoritiesByLogin(String login) {
|
||||
return userRepository.findOneWithAuthoritiesByLogin(login);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public User getUserWithAuthorities(Long id) {
|
||||
return userRepository.findOneWithAuthoritiesById(id);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public User getUserWithAuthorities() {
|
||||
return userRepository.findOneWithAuthoritiesByLogin(SecurityUtils.getCurrentUserLogin()).orElse(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Not activated users should be automatically deleted after 3 days.
|
||||
* <p>
|
||||
* This is scheduled to get fired everyday, at 01:00 (am).
|
||||
* </p>
|
||||
*/
|
||||
@Scheduled(cron = "0 0 1 * * ?")
|
||||
public void removeNotActivatedUsers() {
|
||||
ZonedDateTime now = ZonedDateTime.now();
|
||||
List<User> users = userRepository.findAllByActivatedIsFalseAndCreatedDateBefore(now.minusDays(3));
|
||||
for (User user : users) {
|
||||
log.debug("Deleting not activated user {}", user.getLogin());
|
||||
userRepository.delete(user);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
package com.baeldung.service.dto;
|
||||
|
||||
import com.baeldung.config.Constants;
|
||||
|
||||
import com.baeldung.domain.Authority;
|
||||
import com.baeldung.domain.User;
|
||||
|
||||
import org.hibernate.validator.constraints.Email;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A DTO representing a user, with his authorities.
|
||||
*/
|
||||
public class UserDTO {
|
||||
|
||||
private Long id;
|
||||
|
||||
@Pattern(regexp = Constants.LOGIN_REGEX)
|
||||
@Size(min = 1, max = 50)
|
||||
private String login;
|
||||
|
||||
@Size(max = 50)
|
||||
private String firstName;
|
||||
|
||||
@Size(max = 50)
|
||||
private String lastName;
|
||||
|
||||
@Email
|
||||
@Size(min = 5, max = 100)
|
||||
private String email;
|
||||
|
||||
@Size(max = 256)
|
||||
private String imageUrl;
|
||||
|
||||
private boolean activated = false;
|
||||
|
||||
@Size(min = 2, max = 5)
|
||||
private String langKey;
|
||||
|
||||
private String createdBy;
|
||||
|
||||
private ZonedDateTime createdDate;
|
||||
|
||||
private String lastModifiedBy;
|
||||
|
||||
private ZonedDateTime lastModifiedDate;
|
||||
|
||||
private Set<String> authorities;
|
||||
|
||||
public UserDTO() {
|
||||
// Empty constructor needed for MapStruct.
|
||||
}
|
||||
|
||||
public UserDTO(User user) {
|
||||
this(user.getId(), user.getLogin(), user.getFirstName(), user.getLastName(),
|
||||
user.getEmail(), user.getActivated(), user.getImageUrl(), user.getLangKey(),
|
||||
user.getCreatedBy(), user.getCreatedDate(), user.getLastModifiedBy(), user.getLastModifiedDate(),
|
||||
user.getAuthorities().stream().map(Authority::getName)
|
||||
.collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
public UserDTO(Long id, String login, String firstName, String lastName,
|
||||
String email, boolean activated, String imageUrl, String langKey,
|
||||
String createdBy, ZonedDateTime createdDate, String lastModifiedBy, ZonedDateTime lastModifiedDate,
|
||||
Set<String> authorities) {
|
||||
|
||||
this.id = id;
|
||||
this.login = login;
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.email = email;
|
||||
this.activated = activated;
|
||||
this.imageUrl = imageUrl;
|
||||
this.langKey = langKey;
|
||||
this.createdBy = createdBy;
|
||||
this.createdDate = createdDate;
|
||||
this.lastModifiedBy = lastModifiedBy;
|
||||
this.lastModifiedDate = lastModifiedDate;
|
||||
this.authorities = authorities;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
public void setLogin(String login) {
|
||||
this.login = login;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String getImageUrl() {
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
public boolean isActivated() {
|
||||
return activated;
|
||||
}
|
||||
|
||||
public String getLangKey() {
|
||||
return langKey;
|
||||
}
|
||||
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
|
||||
public ZonedDateTime getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
public String getLastModifiedBy() {
|
||||
return lastModifiedBy;
|
||||
}
|
||||
|
||||
public ZonedDateTime getLastModifiedDate() {
|
||||
return lastModifiedDate;
|
||||
}
|
||||
|
||||
public void setLastModifiedDate(ZonedDateTime lastModifiedDate) {
|
||||
this.lastModifiedDate = lastModifiedDate;
|
||||
}
|
||||
|
||||
public Set<String> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UserDTO{" +
|
||||
"login='" + login + '\'' +
|
||||
", firstName='" + firstName + '\'' +
|
||||
", lastName='" + lastName + '\'' +
|
||||
", email='" + email + '\'' +
|
||||
", imageUrl='" + imageUrl + '\'' +
|
||||
", activated=" + activated +
|
||||
", langKey='" + langKey + '\'' +
|
||||
", createdBy=" + createdBy +
|
||||
", createdDate=" + createdDate +
|
||||
", lastModifiedBy='" + lastModifiedBy + '\'' +
|
||||
", lastModifiedDate=" + lastModifiedDate +
|
||||
", authorities=" + authorities +
|
||||
"}";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Data Transfer Objects.
|
||||
*/
|
||||
package com.baeldung.service.dto;
|
|
@ -0,0 +1,55 @@
|
|||
package com.baeldung.service.mapper;
|
||||
|
||||
import com.baeldung.domain.Authority;
|
||||
import com.baeldung.domain.User;
|
||||
import com.baeldung.service.dto.UserDTO;
|
||||
import org.mapstruct.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Mapper for the entity User and its DTO UserDTO.
|
||||
*/
|
||||
@Mapper(componentModel = "spring", uses = {})
|
||||
public interface UserMapper {
|
||||
|
||||
UserDTO userToUserDTO(User user);
|
||||
|
||||
List<UserDTO> usersToUserDTOs(List<User> users);
|
||||
|
||||
@Mapping(target = "createdBy", ignore = true)
|
||||
@Mapping(target = "createdDate", ignore = true)
|
||||
@Mapping(target = "lastModifiedBy", ignore = true)
|
||||
@Mapping(target = "lastModifiedDate", ignore = true)
|
||||
@Mapping(target = "activationKey", ignore = true)
|
||||
@Mapping(target = "resetKey", ignore = true)
|
||||
@Mapping(target = "resetDate", ignore = true)
|
||||
@Mapping(target = "password", ignore = true)
|
||||
User userDTOToUser(UserDTO userDTO);
|
||||
|
||||
List<User> userDTOsToUsers(List<UserDTO> userDTOs);
|
||||
|
||||
default User userFromId(Long id) {
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
User user = new User();
|
||||
user.setId(id);
|
||||
return user;
|
||||
}
|
||||
|
||||
default Set<String> stringsFromAuthorities (Set<Authority> authorities) {
|
||||
return authorities.stream().map(Authority::getName)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
default Set<Authority> authoritiesFromStrings(Set<String> strings) {
|
||||
return strings.stream().map(string -> {
|
||||
Authority auth = new Authority();
|
||||
auth.setName(string);
|
||||
return auth;
|
||||
}).collect(Collectors.toSet());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* MapStruct mappers for mapping domain objects and Data Transfer Objects.
|
||||
*/
|
||||
package com.baeldung.service.mapper;
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Service layer beans.
|
||||
*/
|
||||
package com.baeldung.service;
|
|
@ -0,0 +1,41 @@
|
|||
package com.baeldung.service.util;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
|
||||
/**
|
||||
* Utility class for generating random Strings.
|
||||
*/
|
||||
public final class RandomUtil {
|
||||
|
||||
private static final int DEF_COUNT = 20;
|
||||
|
||||
private RandomUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a password.
|
||||
*
|
||||
* @return the generated password
|
||||
*/
|
||||
public static String generatePassword() {
|
||||
return RandomStringUtils.randomAlphanumeric(DEF_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an activation key.
|
||||
*
|
||||
* @return the generated activation key
|
||||
*/
|
||||
public static String generateActivationKey() {
|
||||
return RandomStringUtils.randomNumeric(DEF_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a reset key.
|
||||
*
|
||||
* @return the generated reset key
|
||||
*/
|
||||
public static String generateResetKey() {
|
||||
return RandomStringUtils.randomNumeric(DEF_COUNT);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
package com.baeldung.web.rest;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
|
||||
import com.baeldung.domain.User;
|
||||
import com.baeldung.repository.UserRepository;
|
||||
import com.baeldung.security.SecurityUtils;
|
||||
import com.baeldung.service.MailService;
|
||||
import com.baeldung.service.UserService;
|
||||
import com.baeldung.service.dto.UserDTO;
|
||||
import com.baeldung.web.rest.vm.KeyAndPasswordVM;
|
||||
import com.baeldung.web.rest.vm.ManagedUserVM;
|
||||
import com.baeldung.web.rest.util.HeaderUtil;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.Valid;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* REST controller for managing the current user's account.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class AccountResource {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(AccountResource.class);
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
private final UserService userService;
|
||||
|
||||
private final MailService mailService;
|
||||
|
||||
public AccountResource(UserRepository userRepository, UserService userService,
|
||||
MailService mailService) {
|
||||
|
||||
this.userRepository = userRepository;
|
||||
this.userService = userService;
|
||||
this.mailService = mailService;
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /register : register the user.
|
||||
*
|
||||
* @param managedUserVM the managed user View Model
|
||||
* @return the ResponseEntity with status 201 (Created) if the user is registered or 400 (Bad Request) if the login or e-mail is already in use
|
||||
*/
|
||||
@PostMapping(path = "/register",
|
||||
produces={MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_PLAIN_VALUE})
|
||||
@Timed
|
||||
public ResponseEntity registerAccount(@Valid @RequestBody ManagedUserVM managedUserVM) {
|
||||
|
||||
HttpHeaders textPlainHeaders = new HttpHeaders();
|
||||
textPlainHeaders.setContentType(MediaType.TEXT_PLAIN);
|
||||
|
||||
return userRepository.findOneByLogin(managedUserVM.getLogin().toLowerCase())
|
||||
.map(user -> new ResponseEntity<>("login already in use", textPlainHeaders, HttpStatus.BAD_REQUEST))
|
||||
.orElseGet(() -> userRepository.findOneByEmail(managedUserVM.getEmail())
|
||||
.map(user -> new ResponseEntity<>("e-mail address already in use", textPlainHeaders, HttpStatus.BAD_REQUEST))
|
||||
.orElseGet(() -> {
|
||||
User user = userService
|
||||
.createUser(managedUserVM.getLogin(), managedUserVM.getPassword(),
|
||||
managedUserVM.getFirstName(), managedUserVM.getLastName(),
|
||||
managedUserVM.getEmail().toLowerCase(), managedUserVM.getImageUrl(), managedUserVM.getLangKey());
|
||||
|
||||
mailService.sendActivationEmail(user);
|
||||
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /activate : activate the registered user.
|
||||
*
|
||||
* @param key the activation key
|
||||
* @return the ResponseEntity with status 200 (OK) and the activated user in body, or status 500 (Internal Server Error) if the user couldn't be activated
|
||||
*/
|
||||
@GetMapping("/activate")
|
||||
@Timed
|
||||
public ResponseEntity<String> activateAccount(@RequestParam(value = "key") String key) {
|
||||
return userService.activateRegistration(key)
|
||||
.map(user -> new ResponseEntity<String>(HttpStatus.OK))
|
||||
.orElse(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /authenticate : check if the user is authenticated, and return its login.
|
||||
*
|
||||
* @param request the HTTP request
|
||||
* @return the login if the user is authenticated
|
||||
*/
|
||||
@GetMapping("/authenticate")
|
||||
@Timed
|
||||
public String isAuthenticated(HttpServletRequest request) {
|
||||
log.debug("REST request to check if the current user is authenticated");
|
||||
return request.getRemoteUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /account : get the current user.
|
||||
*
|
||||
* @return the ResponseEntity with status 200 (OK) and the current user in body, or status 500 (Internal Server Error) if the user couldn't be returned
|
||||
*/
|
||||
@GetMapping("/account")
|
||||
@Timed
|
||||
public ResponseEntity<UserDTO> getAccount() {
|
||||
return Optional.ofNullable(userService.getUserWithAuthorities())
|
||||
.map(user -> new ResponseEntity<>(new UserDTO(user), HttpStatus.OK))
|
||||
.orElse(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /account : update the current user information.
|
||||
*
|
||||
* @param userDTO the current user information
|
||||
* @return the ResponseEntity with status 200 (OK), or status 400 (Bad Request) or 500 (Internal Server Error) if the user couldn't be updated
|
||||
*/
|
||||
@PostMapping("/account")
|
||||
@Timed
|
||||
public ResponseEntity saveAccount(@Valid @RequestBody UserDTO userDTO) {
|
||||
Optional<User> existingUser = userRepository.findOneByEmail(userDTO.getEmail());
|
||||
if (existingUser.isPresent() && (!existingUser.get().getLogin().equalsIgnoreCase(userDTO.getLogin()))) {
|
||||
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert("user-management", "emailexists", "Email already in use")).body(null);
|
||||
}
|
||||
return userRepository
|
||||
.findOneByLogin(SecurityUtils.getCurrentUserLogin())
|
||||
.map(u -> {
|
||||
userService.updateUser(userDTO.getFirstName(), userDTO.getLastName(), userDTO.getEmail(),
|
||||
userDTO.getLangKey());
|
||||
return new ResponseEntity(HttpStatus.OK);
|
||||
})
|
||||
.orElseGet(() -> new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /account/change_password : changes the current user's password
|
||||
*
|
||||
* @param password the new password
|
||||
* @return the ResponseEntity with status 200 (OK), or status 400 (Bad Request) if the new password is not strong enough
|
||||
*/
|
||||
@PostMapping(path = "/account/change_password",
|
||||
produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
@Timed
|
||||
public ResponseEntity changePassword(@RequestBody String password) {
|
||||
if (!checkPasswordLength(password)) {
|
||||
return new ResponseEntity<>("Incorrect password", HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
userService.changePassword(password);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /account/reset_password/init : Send an e-mail to reset the password of the user
|
||||
*
|
||||
* @param mail the mail of the user
|
||||
* @return the ResponseEntity with status 200 (OK) if the e-mail was sent, or status 400 (Bad Request) if the e-mail address is not registered
|
||||
*/
|
||||
@PostMapping(path = "/account/reset_password/init",
|
||||
produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
@Timed
|
||||
public ResponseEntity requestPasswordReset(@RequestBody String mail) {
|
||||
return userService.requestPasswordReset(mail)
|
||||
.map(user -> {
|
||||
mailService.sendPasswordResetMail(user);
|
||||
return new ResponseEntity<>("e-mail was sent", HttpStatus.OK);
|
||||
}).orElse(new ResponseEntity<>("e-mail address not registered", HttpStatus.BAD_REQUEST));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /account/reset_password/finish : Finish to reset the password of the user
|
||||
*
|
||||
* @param keyAndPassword the generated key and the new password
|
||||
* @return the ResponseEntity with status 200 (OK) if the password has been reset,
|
||||
* or status 400 (Bad Request) or 500 (Internal Server Error) if the password could not be reset
|
||||
*/
|
||||
@PostMapping(path = "/account/reset_password/finish",
|
||||
produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
@Timed
|
||||
public ResponseEntity<String> finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) {
|
||||
if (!checkPasswordLength(keyAndPassword.getNewPassword())) {
|
||||
return new ResponseEntity<>("Incorrect password", HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
return userService.completePasswordReset(keyAndPassword.getNewPassword(), keyAndPassword.getKey())
|
||||
.map(user -> new ResponseEntity<String>(HttpStatus.OK))
|
||||
.orElse(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR));
|
||||
}
|
||||
|
||||
private boolean checkPasswordLength(String password) {
|
||||
return !StringUtils.isEmpty(password) &&
|
||||
password.length() >= ManagedUserVM.PASSWORD_MIN_LENGTH &&
|
||||
password.length() <= ManagedUserVM.PASSWORD_MAX_LENGTH;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package com.baeldung.web.rest;
|
||||
|
||||
import com.baeldung.service.AuditEventService;
|
||||
import com.baeldung.web.rest.util.PaginationUtil;
|
||||
|
||||
import io.github.jhipster.web.util.ResponseUtil;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import org.springframework.boot.actuate.audit.AuditEvent;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* REST controller for getting the audit events.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/management/audits")
|
||||
public class AuditResource {
|
||||
|
||||
private final AuditEventService auditEventService;
|
||||
|
||||
public AuditResource(AuditEventService auditEventService) {
|
||||
this.auditEventService = auditEventService;
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /audits : get a page of AuditEvents.
|
||||
*
|
||||
* @param pageable the pagination information
|
||||
* @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseEntity<List<AuditEvent>> getAll(@ApiParam Pageable pageable) {
|
||||
Page<AuditEvent> page = auditEventService.findAll(pageable);
|
||||
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits");
|
||||
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /audits : get a page of AuditEvents between the fromDate and toDate.
|
||||
*
|
||||
* @param fromDate the start of the time period of AuditEvents to get
|
||||
* @param toDate the end of the time period of AuditEvents to get
|
||||
* @param pageable the pagination information
|
||||
* @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body
|
||||
*/
|
||||
|
||||
@GetMapping(params = {"fromDate", "toDate"})
|
||||
public ResponseEntity<List<AuditEvent>> getByDates(
|
||||
@RequestParam(value = "fromDate") LocalDate fromDate,
|
||||
@RequestParam(value = "toDate") LocalDate toDate,
|
||||
@ApiParam Pageable pageable) {
|
||||
|
||||
Page<AuditEvent> page = auditEventService.findByDates(fromDate.atTime(0, 0), toDate.atTime(23, 59), pageable);
|
||||
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits");
|
||||
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /audits/:id : get an AuditEvent by id.
|
||||
*
|
||||
* @param id the id of the entity to get
|
||||
* @return the ResponseEntity with status 200 (OK) and the AuditEvent in body, or status 404 (Not Found)
|
||||
*/
|
||||
@GetMapping("/{id:.+}")
|
||||
public ResponseEntity<AuditEvent> get(@PathVariable Long id) {
|
||||
return ResponseUtil.wrapOrNotFound(auditEventService.find(id));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
package com.baeldung.web.rest;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import com.baeldung.domain.Comment;
|
||||
|
||||
import com.baeldung.repository.CommentRepository;
|
||||
import com.baeldung.web.rest.util.HeaderUtil;
|
||||
import com.baeldung.web.rest.util.PaginationUtil;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import io.github.jhipster.web.util.ResponseUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* REST controller for managing Comment.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class CommentResource {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(CommentResource.class);
|
||||
|
||||
private static final String ENTITY_NAME = "comment";
|
||||
|
||||
private final CommentRepository commentRepository;
|
||||
|
||||
public CommentResource(CommentRepository commentRepository) {
|
||||
this.commentRepository = commentRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /comments : Create a new comment.
|
||||
*
|
||||
* @param comment the comment to create
|
||||
* @return the ResponseEntity with status 201 (Created) and with body the new comment, or with status 400 (Bad Request) if the comment has already an ID
|
||||
* @throws URISyntaxException if the Location URI syntax is incorrect
|
||||
*/
|
||||
@PostMapping("/comments")
|
||||
@Timed
|
||||
public ResponseEntity<Comment> createComment(@Valid @RequestBody Comment comment) throws URISyntaxException {
|
||||
log.debug("REST request to save Comment : {}", comment);
|
||||
if (comment.getId() != null) {
|
||||
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "idexists", "A new comment cannot already have an ID")).body(null);
|
||||
}
|
||||
Comment result = commentRepository.save(comment);
|
||||
return ResponseEntity.created(new URI("/api/comments/" + result.getId()))
|
||||
.headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
|
||||
.body(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /comments : Updates an existing comment.
|
||||
*
|
||||
* @param comment the comment to update
|
||||
* @return the ResponseEntity with status 200 (OK) and with body the updated comment,
|
||||
* or with status 400 (Bad Request) if the comment is not valid,
|
||||
* or with status 500 (Internal Server Error) if the comment couldnt be updated
|
||||
* @throws URISyntaxException if the Location URI syntax is incorrect
|
||||
*/
|
||||
@PutMapping("/comments")
|
||||
@Timed
|
||||
public ResponseEntity<Comment> updateComment(@Valid @RequestBody Comment comment) throws URISyntaxException {
|
||||
log.debug("REST request to update Comment : {}", comment);
|
||||
if (comment.getId() == null) {
|
||||
return createComment(comment);
|
||||
}
|
||||
Comment result = commentRepository.save(comment);
|
||||
return ResponseEntity.ok()
|
||||
.headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, comment.getId().toString()))
|
||||
.body(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /comments : get all the comments.
|
||||
*
|
||||
* @param pageable the pagination information
|
||||
* @return the ResponseEntity with status 200 (OK) and the list of comments in body
|
||||
* @throws URISyntaxException if there is an error to generate the pagination HTTP headers
|
||||
*/
|
||||
@GetMapping("/comments")
|
||||
@Timed
|
||||
public ResponseEntity<List<Comment>> getAllComments(@ApiParam Pageable pageable) {
|
||||
log.debug("REST request to get a page of Comments");
|
||||
Page<Comment> page = commentRepository.findAll(pageable);
|
||||
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/comments");
|
||||
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /comments/:id : get the "id" comment.
|
||||
*
|
||||
* @param id the id of the comment to retrieve
|
||||
* @return the ResponseEntity with status 200 (OK) and with body the comment, or with status 404 (Not Found)
|
||||
*/
|
||||
@GetMapping("/comments/{id}")
|
||||
@Timed
|
||||
public ResponseEntity<Comment> getComment(@PathVariable Long id) {
|
||||
log.debug("REST request to get Comment : {}", id);
|
||||
Comment comment = commentRepository.findOne(id);
|
||||
return ResponseUtil.wrapOrNotFound(Optional.ofNullable(comment));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /comments/:id : delete the "id" comment.
|
||||
*
|
||||
* @param id the id of the comment to delete
|
||||
* @return the ResponseEntity with status 200 (OK)
|
||||
*/
|
||||
@DeleteMapping("/comments/{id}")
|
||||
@Timed
|
||||
public ResponseEntity<Void> deleteComment(@PathVariable Long id) {
|
||||
log.debug("REST request to delete Comment : {}", id);
|
||||
commentRepository.delete(id);
|
||||
return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, id.toString())).build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.web.rest;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Object to return as body in JWT Authentication.
|
||||
*/
|
||||
public class JWTToken {
|
||||
|
||||
private String idToken;
|
||||
|
||||
public JWTToken(String idToken) {
|
||||
this.idToken = idToken;
|
||||
}
|
||||
|
||||
@JsonProperty("id_token")
|
||||
public String getIdToken() {
|
||||
return idToken;
|
||||
}
|
||||
|
||||
public void setIdToken(String idToken) {
|
||||
this.idToken = idToken;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.baeldung.web.rest;
|
||||
|
||||
import com.baeldung.web.rest.vm.LoggerVM;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Controller for view and managing Log Level at runtime.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/management")
|
||||
public class LogsResource {
|
||||
|
||||
@GetMapping("/logs")
|
||||
@Timed
|
||||
public List<LoggerVM> getList() {
|
||||
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
return context.getLoggerList()
|
||||
.stream()
|
||||
.map(LoggerVM::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@PutMapping("/logs")
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@Timed
|
||||
public void changeLevel(@RequestBody LoggerVM jsonLogger) {
|
||||
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
context.getLogger(jsonLogger.getName()).setLevel(Level.valueOf(jsonLogger.getLevel()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
package com.baeldung.web.rest;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import com.baeldung.domain.Post;
|
||||
|
||||
import com.baeldung.repository.PostRepository;
|
||||
import com.baeldung.web.rest.util.HeaderUtil;
|
||||
import com.baeldung.web.rest.util.PaginationUtil;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import io.github.jhipster.web.util.ResponseUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* REST controller for managing Post.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class PostResource {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(PostResource.class);
|
||||
|
||||
private static final String ENTITY_NAME = "post";
|
||||
|
||||
private final PostRepository postRepository;
|
||||
|
||||
public PostResource(PostRepository postRepository) {
|
||||
this.postRepository = postRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /posts : Create a new post.
|
||||
*
|
||||
* @param post the post to create
|
||||
* @return the ResponseEntity with status 201 (Created) and with body the new post, or with status 400 (Bad Request) if the post has already an ID
|
||||
* @throws URISyntaxException if the Location URI syntax is incorrect
|
||||
*/
|
||||
@PostMapping("/posts")
|
||||
@Timed
|
||||
public ResponseEntity<Post> createPost(@Valid @RequestBody Post post) throws URISyntaxException {
|
||||
log.debug("REST request to save Post : {}", post);
|
||||
if (post.getId() != null) {
|
||||
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "idexists", "A new post cannot already have an ID")).body(null);
|
||||
}
|
||||
Post result = postRepository.save(post);
|
||||
return ResponseEntity.created(new URI("/api/posts/" + result.getId()))
|
||||
.headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
|
||||
.body(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /posts : Updates an existing post.
|
||||
*
|
||||
* @param post the post to update
|
||||
* @return the ResponseEntity with status 200 (OK) and with body the updated post,
|
||||
* or with status 400 (Bad Request) if the post is not valid,
|
||||
* or with status 500 (Internal Server Error) if the post couldnt be updated
|
||||
* @throws URISyntaxException if the Location URI syntax is incorrect
|
||||
*/
|
||||
@PutMapping("/posts")
|
||||
@Timed
|
||||
public ResponseEntity<Post> updatePost(@Valid @RequestBody Post post) throws URISyntaxException {
|
||||
log.debug("REST request to update Post : {}", post);
|
||||
if (post.getId() == null) {
|
||||
return createPost(post);
|
||||
}
|
||||
Post result = postRepository.save(post);
|
||||
return ResponseEntity.ok()
|
||||
.headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, post.getId().toString()))
|
||||
.body(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /posts : get all the posts.
|
||||
*
|
||||
* @param pageable the pagination information
|
||||
* @return the ResponseEntity with status 200 (OK) and the list of posts in body
|
||||
* @throws URISyntaxException if there is an error to generate the pagination HTTP headers
|
||||
*/
|
||||
@GetMapping("/posts")
|
||||
@Timed
|
||||
public ResponseEntity<List<Post>> getAllPosts(@ApiParam Pageable pageable) {
|
||||
log.debug("REST request to get a page of Posts");
|
||||
Page<Post> page = postRepository.findAll(pageable);
|
||||
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/posts");
|
||||
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /posts/:id : get the "id" post.
|
||||
*
|
||||
* @param id the id of the post to retrieve
|
||||
* @return the ResponseEntity with status 200 (OK) and with body the post, or with status 404 (Not Found)
|
||||
*/
|
||||
@GetMapping("/posts/{id}")
|
||||
@Timed
|
||||
public ResponseEntity<Post> getPost(@PathVariable Long id) {
|
||||
log.debug("REST request to get Post : {}", id);
|
||||
Post post = postRepository.findOne(id);
|
||||
return ResponseUtil.wrapOrNotFound(Optional.ofNullable(post));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /posts/:id : delete the "id" post.
|
||||
*
|
||||
* @param id the id of the post to delete
|
||||
* @return the ResponseEntity with status 200 (OK)
|
||||
*/
|
||||
@DeleteMapping("/posts/{id}")
|
||||
@Timed
|
||||
public ResponseEntity<Void> deletePost(@PathVariable Long id) {
|
||||
log.debug("REST request to delete Post : {}", id);
|
||||
postRepository.delete(id);
|
||||
return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, id.toString())).build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package com.baeldung.web.rest;
|
||||
|
||||
import com.baeldung.config.DefaultProfileUtil;
|
||||
|
||||
import io.github.jhipster.config.JHipsterProperties;
|
||||
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Resource to return information about the currently running Spring profiles.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class ProfileInfoResource {
|
||||
|
||||
private final Environment env;
|
||||
|
||||
private final JHipsterProperties jHipsterProperties;
|
||||
|
||||
public ProfileInfoResource(Environment env, JHipsterProperties jHipsterProperties) {
|
||||
this.env = env;
|
||||
this.jHipsterProperties = jHipsterProperties;
|
||||
}
|
||||
|
||||
@GetMapping("/profile-info")
|
||||
public ProfileInfoVM getActiveProfiles() {
|
||||
String[] activeProfiles = DefaultProfileUtil.getActiveProfiles(env);
|
||||
return new ProfileInfoVM(activeProfiles, getRibbonEnv(activeProfiles));
|
||||
}
|
||||
|
||||
private String getRibbonEnv(String[] activeProfiles) {
|
||||
String[] displayOnActiveProfiles = jHipsterProperties.getRibbon().getDisplayOnActiveProfiles();
|
||||
if (displayOnActiveProfiles == null) {
|
||||
return null;
|
||||
}
|
||||
List<String> ribbonProfiles = new ArrayList<>(Arrays.asList(displayOnActiveProfiles));
|
||||
List<String> springBootProfiles = Arrays.asList(activeProfiles);
|
||||
ribbonProfiles.retainAll(springBootProfiles);
|
||||
if (!ribbonProfiles.isEmpty()) {
|
||||
return ribbonProfiles.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
class ProfileInfoVM {
|
||||
|
||||
private String[] activeProfiles;
|
||||
|
||||
private String ribbonEnv;
|
||||
|
||||
ProfileInfoVM(String[] activeProfiles, String ribbonEnv) {
|
||||
this.activeProfiles = activeProfiles;
|
||||
this.ribbonEnv = ribbonEnv;
|
||||
}
|
||||
|
||||
public String[] getActiveProfiles() {
|
||||
return activeProfiles;
|
||||
}
|
||||
|
||||
public String getRibbonEnv() {
|
||||
return ribbonEnv;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.baeldung.web.rest;
|
||||
|
||||
import com.baeldung.security.jwt.JWTConfigurer;
|
||||
import com.baeldung.security.jwt.TokenProvider;
|
||||
import com.baeldung.web.rest.vm.LoginVM;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class UserJWTController {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(UserJWTController.class);
|
||||
|
||||
private final TokenProvider tokenProvider;
|
||||
|
||||
private final AuthenticationManager authenticationManager;
|
||||
|
||||
public UserJWTController(TokenProvider tokenProvider, AuthenticationManager authenticationManager) {
|
||||
this.tokenProvider = tokenProvider;
|
||||
this.authenticationManager = authenticationManager;
|
||||
}
|
||||
|
||||
@PostMapping("/authenticate")
|
||||
@Timed
|
||||
public ResponseEntity authorize(@Valid @RequestBody LoginVM loginVM, HttpServletResponse response) {
|
||||
|
||||
UsernamePasswordAuthenticationToken authenticationToken =
|
||||
new UsernamePasswordAuthenticationToken(loginVM.getUsername(), loginVM.getPassword());
|
||||
|
||||
try {
|
||||
Authentication authentication = this.authenticationManager.authenticate(authenticationToken);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
boolean rememberMe = (loginVM.isRememberMe() == null) ? false : loginVM.isRememberMe();
|
||||
String jwt = tokenProvider.createToken(authentication, rememberMe);
|
||||
response.addHeader(JWTConfigurer.AUTHORIZATION_HEADER, "Bearer " + jwt);
|
||||
return ResponseEntity.ok(new JWTToken(jwt));
|
||||
} catch (AuthenticationException ae) {
|
||||
log.trace("Authentication exception trace: {}", ae);
|
||||
return new ResponseEntity<>(Collections.singletonMap("AuthenticationException",
|
||||
ae.getLocalizedMessage()), HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
package com.baeldung.web.rest;
|
||||
|
||||
import com.baeldung.config.Constants;
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import com.baeldung.domain.User;
|
||||
import com.baeldung.repository.UserRepository;
|
||||
import com.baeldung.security.AuthoritiesConstants;
|
||||
import com.baeldung.service.MailService;
|
||||
import com.baeldung.service.UserService;
|
||||
import com.baeldung.service.dto.UserDTO;
|
||||
import com.baeldung.web.rest.vm.ManagedUserVM;
|
||||
import com.baeldung.web.rest.util.HeaderUtil;
|
||||
import com.baeldung.web.rest.util.PaginationUtil;
|
||||
import io.github.jhipster.web.util.ResponseUtil;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* REST controller for managing users.
|
||||
*
|
||||
* <p>This class accesses the User entity, and needs to fetch its collection of authorities.</p>
|
||||
* <p>
|
||||
* For a normal use-case, it would be better to have an eager relationship between User and Authority,
|
||||
* and send everything to the client side: there would be no View Model and DTO, a lot less code, and an outer-join
|
||||
* which would be good for performance.
|
||||
* </p>
|
||||
* <p>
|
||||
* We use a View Model and a DTO for 3 reasons:
|
||||
* <ul>
|
||||
* <li>We want to keep a lazy association between the user and the authorities, because people will
|
||||
* quite often do relationships with the user, and we don't want them to get the authorities all
|
||||
* the time for nothing (for performance reasons). This is the #1 goal: we should not impact our users'
|
||||
* application because of this use-case.</li>
|
||||
* <li> Not having an outer join causes n+1 requests to the database. This is not a real issue as
|
||||
* we have by default a second-level cache. This means on the first HTTP call we do the n+1 requests,
|
||||
* but then all authorities come from the cache, so in fact it's much better than doing an outer join
|
||||
* (which will get lots of data from the database, for each HTTP call).</li>
|
||||
* <li> As this manages users, for security reasons, we'd rather have a DTO layer.</li>
|
||||
* </ul>
|
||||
* <p>Another option would be to have a specific JPA entity graph to handle this case.</p>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class UserResource {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(UserResource.class);
|
||||
|
||||
private static final String ENTITY_NAME = "userManagement";
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
private final MailService mailService;
|
||||
|
||||
private final UserService userService;
|
||||
|
||||
public UserResource(UserRepository userRepository, MailService mailService,
|
||||
UserService userService) {
|
||||
|
||||
this.userRepository = userRepository;
|
||||
this.mailService = mailService;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /users : Creates a new user.
|
||||
* <p>
|
||||
* Creates a new user if the login and email are not already used, and sends an
|
||||
* mail with an activation link.
|
||||
* The user needs to be activated on creation.
|
||||
* </p>
|
||||
*
|
||||
* @param managedUserVM the user to create
|
||||
* @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
|
||||
* @throws URISyntaxException if the Location URI syntax is incorrect
|
||||
*/
|
||||
@PostMapping("/users")
|
||||
@Timed
|
||||
@Secured(AuthoritiesConstants.ADMIN)
|
||||
public ResponseEntity createUser(@RequestBody ManagedUserVM managedUserVM) throws URISyntaxException {
|
||||
log.debug("REST request to save User : {}", managedUserVM);
|
||||
|
||||
if (managedUserVM.getId() != null) {
|
||||
return ResponseEntity.badRequest()
|
||||
.headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "idexists", "A new user cannot already have an ID"))
|
||||
.body(null);
|
||||
// Lowercase the user login before comparing with database
|
||||
} else if (userRepository.findOneByLogin(managedUserVM.getLogin().toLowerCase()).isPresent()) {
|
||||
return ResponseEntity.badRequest()
|
||||
.headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "userexists", "Login already in use"))
|
||||
.body(null);
|
||||
} else if (userRepository.findOneByEmail(managedUserVM.getEmail()).isPresent()) {
|
||||
return ResponseEntity.badRequest()
|
||||
.headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "emailexists", "Email already in use"))
|
||||
.body(null);
|
||||
} else {
|
||||
User newUser = userService.createUser(managedUserVM);
|
||||
mailService.sendCreationEmail(newUser);
|
||||
return ResponseEntity.created(new URI("/api/users/" + newUser.getLogin()))
|
||||
.headers(HeaderUtil.createAlert( "userManagement.created", newUser.getLogin()))
|
||||
.body(newUser);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /users : Updates an existing User.
|
||||
*
|
||||
* @param managedUserVM the user to update
|
||||
* @return the ResponseEntity with status 200 (OK) and with body the updated user,
|
||||
* or with status 400 (Bad Request) if the login or email is already in use,
|
||||
* or with status 500 (Internal Server Error) if the user couldn't be updated
|
||||
*/
|
||||
@PutMapping("/users")
|
||||
@Timed
|
||||
@Secured(AuthoritiesConstants.ADMIN)
|
||||
public ResponseEntity<UserDTO> updateUser(@RequestBody ManagedUserVM managedUserVM) {
|
||||
log.debug("REST request to update User : {}", managedUserVM);
|
||||
Optional<User> existingUser = userRepository.findOneByEmail(managedUserVM.getEmail());
|
||||
if (existingUser.isPresent() && (!existingUser.get().getId().equals(managedUserVM.getId()))) {
|
||||
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "emailexists", "E-mail already in use")).body(null);
|
||||
}
|
||||
existingUser = userRepository.findOneByLogin(managedUserVM.getLogin().toLowerCase());
|
||||
if (existingUser.isPresent() && (!existingUser.get().getId().equals(managedUserVM.getId()))) {
|
||||
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "userexists", "Login already in use")).body(null);
|
||||
}
|
||||
Optional<UserDTO> updatedUser = userService.updateUser(managedUserVM);
|
||||
|
||||
return ResponseUtil.wrapOrNotFound(updatedUser,
|
||||
HeaderUtil.createAlert("userManagement.updated", managedUserVM.getLogin()));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /users : get all users.
|
||||
*
|
||||
* @param pageable the pagination information
|
||||
* @return the ResponseEntity with status 200 (OK) and with body all users
|
||||
*/
|
||||
@GetMapping("/users")
|
||||
@Timed
|
||||
public ResponseEntity<List<UserDTO>> getAllUsers(@ApiParam Pageable pageable) {
|
||||
final Page<UserDTO> page = userService.getAllManagedUsers(pageable);
|
||||
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/users");
|
||||
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /users/:login : get the "login" user.
|
||||
*
|
||||
* @param login the login of the user to find
|
||||
* @return the ResponseEntity with status 200 (OK) and with body the "login" user, or with status 404 (Not Found)
|
||||
*/
|
||||
@GetMapping("/users/{login:" + Constants.LOGIN_REGEX + "}")
|
||||
@Timed
|
||||
public ResponseEntity<UserDTO> getUser(@PathVariable String login) {
|
||||
log.debug("REST request to get User : {}", login);
|
||||
return ResponseUtil.wrapOrNotFound(
|
||||
userService.getUserWithAuthoritiesByLogin(login)
|
||||
.map(UserDTO::new));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /users/:login : delete the "login" User.
|
||||
*
|
||||
* @param login the login of the user to delete
|
||||
* @return the ResponseEntity with status 200 (OK)
|
||||
*/
|
||||
@DeleteMapping("/users/{login:" + Constants.LOGIN_REGEX + "}")
|
||||
@Timed
|
||||
@Secured(AuthoritiesConstants.ADMIN)
|
||||
public ResponseEntity<Void> deleteUser(@PathVariable String login) {
|
||||
log.debug("REST request to delete User: {}", login);
|
||||
userService.deleteUser(login);
|
||||
return ResponseEntity.ok().headers(HeaderUtil.createAlert( "userManagement.deleted", login)).build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.baeldung.web.rest.errors;
|
||||
|
||||
/**
|
||||
* Custom, parameterized exception, which can be translated on the client side.
|
||||
* For example:
|
||||
*
|
||||
* <pre>
|
||||
* throw new CustomParameterizedException("myCustomError", "hello", "world");
|
||||
* </pre>
|
||||
*
|
||||
* Can be translated with:
|
||||
*
|
||||
* <pre>
|
||||
* "error.myCustomError" : "The server says {{params[0]}} to {{params[1]}}"
|
||||
* </pre>
|
||||
*/
|
||||
public class CustomParameterizedException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String message;
|
||||
private final String[] params;
|
||||
|
||||
public CustomParameterizedException(String message, String... params) {
|
||||
super(message);
|
||||
this.message = message;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public ParameterizedErrorVM getErrorVM() {
|
||||
return new ParameterizedErrorVM(message, params);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.web.rest.errors;
|
||||
|
||||
public final class ErrorConstants {
|
||||
|
||||
public static final String ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure";
|
||||
public static final String ERR_ACCESS_DENIED = "error.accessDenied";
|
||||
public static final String ERR_VALIDATION = "error.validation";
|
||||
public static final String ERR_METHOD_NOT_SUPPORTED = "error.methodNotSupported";
|
||||
public static final String ERR_INTERNAL_SERVER_ERROR = "error.internalServerError";
|
||||
|
||||
private ErrorConstants() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.baeldung.web.rest.errors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* View Model for transferring error message with a list of field errors.
|
||||
*/
|
||||
public class ErrorVM implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String message;
|
||||
private final String description;
|
||||
|
||||
private List<FieldErrorVM> fieldErrors;
|
||||
|
||||
public ErrorVM(String message) {
|
||||
this(message, null);
|
||||
}
|
||||
|
||||
public ErrorVM(String message, String description) {
|
||||
this.message = message;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public ErrorVM(String message, String description, List<FieldErrorVM> fieldErrors) {
|
||||
this.message = message;
|
||||
this.description = description;
|
||||
this.fieldErrors = fieldErrors;
|
||||
}
|
||||
|
||||
public void add(String objectName, String field, String message) {
|
||||
if (fieldErrors == null) {
|
||||
fieldErrors = new ArrayList<>();
|
||||
}
|
||||
fieldErrors.add(new FieldErrorVM(objectName, field, message));
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public List<FieldErrorVM> getFieldErrors() {
|
||||
return fieldErrors;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package com.baeldung.web.rest.errors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.ResponseEntity.BodyBuilder;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* Controller advice to translate the server side exceptions to client-friendly json structures.
|
||||
*/
|
||||
@ControllerAdvice
|
||||
public class ExceptionTranslator {
|
||||
|
||||
@ExceptionHandler(ConcurrencyFailureException.class)
|
||||
@ResponseStatus(HttpStatus.CONFLICT)
|
||||
@ResponseBody
|
||||
public ErrorVM processConcurrencyError(ConcurrencyFailureException ex) {
|
||||
return new ErrorVM(ErrorConstants.ERR_CONCURRENCY_FAILURE);
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ResponseBody
|
||||
public ErrorVM processValidationError(MethodArgumentNotValidException ex) {
|
||||
BindingResult result = ex.getBindingResult();
|
||||
List<FieldError> fieldErrors = result.getFieldErrors();
|
||||
|
||||
return processFieldErrors(fieldErrors);
|
||||
}
|
||||
|
||||
@ExceptionHandler(CustomParameterizedException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ResponseBody
|
||||
public ParameterizedErrorVM processParameterizedValidationError(CustomParameterizedException ex) {
|
||||
return ex.getErrorVM();
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
@ResponseStatus(HttpStatus.FORBIDDEN)
|
||||
@ResponseBody
|
||||
public ErrorVM processAccessDeniedException(AccessDeniedException e) {
|
||||
return new ErrorVM(ErrorConstants.ERR_ACCESS_DENIED, e.getMessage());
|
||||
}
|
||||
|
||||
private ErrorVM processFieldErrors(List<FieldError> fieldErrors) {
|
||||
ErrorVM dto = new ErrorVM(ErrorConstants.ERR_VALIDATION);
|
||||
|
||||
for (FieldError fieldError : fieldErrors) {
|
||||
dto.add(fieldError.getObjectName(), fieldError.getField(), fieldError.getCode());
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
|
||||
@ResponseBody
|
||||
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
|
||||
public ErrorVM processMethodNotSupportedException(HttpRequestMethodNotSupportedException exception) {
|
||||
return new ErrorVM(ErrorConstants.ERR_METHOD_NOT_SUPPORTED, exception.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<ErrorVM> processRuntimeException(Exception ex) {
|
||||
BodyBuilder builder;
|
||||
ErrorVM errorVM;
|
||||
ResponseStatus responseStatus = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class);
|
||||
if (responseStatus != null) {
|
||||
builder = ResponseEntity.status(responseStatus.value());
|
||||
errorVM = new ErrorVM("error." + responseStatus.value().value(), responseStatus.reason());
|
||||
} else {
|
||||
builder = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
errorVM = new ErrorVM(ErrorConstants.ERR_INTERNAL_SERVER_ERROR, "Internal server error");
|
||||
}
|
||||
return builder.body(errorVM);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.baeldung.web.rest.errors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class FieldErrorVM implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String objectName;
|
||||
|
||||
private final String field;
|
||||
|
||||
private final String message;
|
||||
|
||||
public FieldErrorVM(String dto, String field, String message) {
|
||||
this.objectName = dto;
|
||||
this.field = field;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getObjectName() {
|
||||
return objectName;
|
||||
}
|
||||
|
||||
public String getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.web.rest.errors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* View Model for sending a parameterized error message.
|
||||
*/
|
||||
public class ParameterizedErrorVM implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final String message;
|
||||
private final String[] params;
|
||||
|
||||
public ParameterizedErrorVM(String message, String... params) {
|
||||
this.message = message;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String[] getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Spring MVC REST controllers.
|
||||
*/
|
||||
package com.baeldung.web.rest;
|
|
@ -0,0 +1,45 @@
|
|||
package com.baeldung.web.rest.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
|
||||
/**
|
||||
* Utility class for HTTP headers creation.
|
||||
*/
|
||||
public final class HeaderUtil {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HeaderUtil.class);
|
||||
|
||||
private static final String APPLICATION_NAME = "baeldungApp";
|
||||
|
||||
private HeaderUtil() {
|
||||
}
|
||||
|
||||
public static HttpHeaders createAlert(String message, String param) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("X-baeldungApp-alert", message);
|
||||
headers.add("X-baeldungApp-params", param);
|
||||
return headers;
|
||||
}
|
||||
|
||||
public static HttpHeaders createEntityCreationAlert(String entityName, String param) {
|
||||
return createAlert(APPLICATION_NAME + "." + entityName + ".created", param);
|
||||
}
|
||||
|
||||
public static HttpHeaders createEntityUpdateAlert(String entityName, String param) {
|
||||
return createAlert(APPLICATION_NAME + "." + entityName + ".updated", param);
|
||||
}
|
||||
|
||||
public static HttpHeaders createEntityDeletionAlert(String entityName, String param) {
|
||||
return createAlert(APPLICATION_NAME + "." + entityName + ".deleted", param);
|
||||
}
|
||||
|
||||
public static HttpHeaders createFailureAlert(String entityName, String errorKey, String defaultMessage) {
|
||||
log.error("Entity creation failed, {}", defaultMessage);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("X-baeldungApp-error", "error." + errorKey);
|
||||
headers.add("X-baeldungApp-params", entityName);
|
||||
return headers;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.baeldung.web.rest.util;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
/**
|
||||
* Utility class for handling pagination.
|
||||
*
|
||||
* <p>
|
||||
* Pagination uses the same principles as the <a href="https://developer.github.com/v3/#pagination">Github API</a>,
|
||||
* and follow <a href="http://tools.ietf.org/html/rfc5988">RFC 5988 (Link header)</a>.
|
||||
*/
|
||||
public final class PaginationUtil {
|
||||
|
||||
private PaginationUtil() {
|
||||
}
|
||||
|
||||
public static HttpHeaders generatePaginationHttpHeaders(Page page, String baseUrl) {
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("X-Total-Count", "" + Long.toString(page.getTotalElements()));
|
||||
String link = "";
|
||||
if ((page.getNumber() + 1) < page.getTotalPages()) {
|
||||
link = "<" + generateUri(baseUrl, page.getNumber() + 1, page.getSize()) + ">; rel=\"next\",";
|
||||
}
|
||||
// prev link
|
||||
if ((page.getNumber()) > 0) {
|
||||
link += "<" + generateUri(baseUrl, page.getNumber() - 1, page.getSize()) + ">; rel=\"prev\",";
|
||||
}
|
||||
// last and first link
|
||||
int lastPage = 0;
|
||||
if (page.getTotalPages() > 0) {
|
||||
lastPage = page.getTotalPages() - 1;
|
||||
}
|
||||
link += "<" + generateUri(baseUrl, lastPage, page.getSize()) + ">; rel=\"last\",";
|
||||
link += "<" + generateUri(baseUrl, 0, page.getSize()) + ">; rel=\"first\"";
|
||||
headers.add(HttpHeaders.LINK, link);
|
||||
return headers;
|
||||
}
|
||||
|
||||
private static String generateUri(String baseUrl, int page, int size) {
|
||||
return UriComponentsBuilder.fromUriString(baseUrl).queryParam("page", page).queryParam("size", size).toUriString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.web.rest.vm;
|
||||
|
||||
/**
|
||||
* View Model object for storing the user's key and password.
|
||||
*/
|
||||
public class KeyAndPasswordVM {
|
||||
|
||||
private String key;
|
||||
|
||||
private String newPassword;
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getNewPassword() {
|
||||
return newPassword;
|
||||
}
|
||||
|
||||
public void setNewPassword(String newPassword) {
|
||||
this.newPassword = newPassword;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.baeldung.web.rest.vm;
|
||||
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
|
||||
/**
|
||||
* View Model object for storing a Logback logger.
|
||||
*/
|
||||
public class LoggerVM {
|
||||
|
||||
private String name;
|
||||
|
||||
private String level;
|
||||
|
||||
public LoggerVM(Logger logger) {
|
||||
this.name = logger.getName();
|
||||
this.level = logger.getEffectiveLevel().toString();
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public LoggerVM() {
|
||||
// Empty public constructor used by Jackson.
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(String level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LoggerVM{" +
|
||||
"name='" + name + '\'' +
|
||||
", level='" + level + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.baeldung.web.rest.vm;
|
||||
|
||||
import com.baeldung.config.Constants;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* View Model object for storing a user's credentials.
|
||||
*/
|
||||
public class LoginVM {
|
||||
|
||||
@Pattern(regexp = Constants.LOGIN_REGEX)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 50)
|
||||
private String username;
|
||||
|
||||
@NotNull
|
||||
@Size(min = ManagedUserVM.PASSWORD_MIN_LENGTH, max = ManagedUserVM.PASSWORD_MAX_LENGTH)
|
||||
private String password;
|
||||
|
||||
private Boolean rememberMe;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Boolean isRememberMe() {
|
||||
return rememberMe;
|
||||
}
|
||||
|
||||
public void setRememberMe(Boolean rememberMe) {
|
||||
this.rememberMe = rememberMe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LoginVM{" +
|
||||
"username='" + username + '\'' +
|
||||
", rememberMe=" + rememberMe +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.baeldung.web.rest.vm;
|
||||
|
||||
import com.baeldung.service.dto.UserDTO;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* View Model extending the UserDTO, which is meant to be used in the user management UI.
|
||||
*/
|
||||
public class ManagedUserVM extends UserDTO {
|
||||
|
||||
public static final int PASSWORD_MIN_LENGTH = 4;
|
||||
|
||||
public static final int PASSWORD_MAX_LENGTH = 100;
|
||||
|
||||
@Size(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH)
|
||||
private String password;
|
||||
|
||||
public ManagedUserVM() {
|
||||
// Empty constructor needed for Jackson.
|
||||
}
|
||||
|
||||
public ManagedUserVM(Long id, String login, String password, String firstName, String lastName,
|
||||
String email, boolean activated, String imageUrl, String langKey,
|
||||
String createdBy, ZonedDateTime createdDate, String lastModifiedBy, ZonedDateTime lastModifiedDate,
|
||||
Set<String> authorities) {
|
||||
|
||||
super(id, login, firstName, lastName, email, activated, imageUrl, langKey,
|
||||
createdBy, createdDate, lastModifiedBy, lastModifiedDate, authorities);
|
||||
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ManagedUserVM{" +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* View Models used by Spring MVC REST controllers.
|
||||
*/
|
||||
package com.baeldung.web.rest.vm;
|
|
@ -0,0 +1,5 @@
|
|||
#H2 Server Properties
|
||||
0=JHipster H2 (Disk)|org.h2.Driver|jdbc\:h2\:file\:./target/h2db/db/baeldung|baeldung
|
||||
webAllowOthers=true
|
||||
webPort=8082
|
||||
webSSL=false
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue