├── .gitignore ├── README.md ├── client-side ├── .editorconfig ├── .gitignore ├── README.md ├── angular.json ├── browserslist ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.json ├── karma.conf.js ├── package.json ├── src │ ├── app │ │ ├── app-routing.module.ts │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── components │ │ │ ├── detail │ │ │ │ ├── detail.component.css │ │ │ │ ├── detail.component.html │ │ │ │ ├── detail.component.spec.ts │ │ │ │ └── detail.component.ts │ │ │ ├── home │ │ │ │ ├── home.component.css │ │ │ │ ├── home.component.html │ │ │ │ ├── home.component.spec.ts │ │ │ │ └── home.component.ts │ │ │ ├── login │ │ │ │ ├── login.component.css │ │ │ │ ├── login.component.html │ │ │ │ ├── login.component.spec.ts │ │ │ │ └── login.component.ts │ │ │ ├── profile │ │ │ │ ├── profile.component.css │ │ │ │ ├── profile.component.html │ │ │ │ ├── profile.component.spec.ts │ │ │ │ └── profile.component.ts │ │ │ └── register │ │ │ │ ├── register.component.css │ │ │ │ ├── register.component.html │ │ │ │ ├── register.component.spec.ts │ │ │ │ └── register.component.ts │ │ ├── models │ │ │ ├── course.ts │ │ │ ├── role.ts │ │ │ ├── transaction.ts │ │ │ └── user.ts │ │ └── services │ │ │ ├── course.service.spec.ts │ │ │ ├── course.service.ts │ │ │ ├── user.service.spec.ts │ │ │ └── user.service.ts │ ├── assets │ │ ├── .gitkeep │ │ └── fonts │ │ │ ├── glyphicons │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ ├── glyphicons-halflings-regular.woff2 │ │ │ └── glyphicons.css │ │ │ └── prettify-angulario.css │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ └── test.ts ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.spec.json └── tslint.json ├── eureka-discovery-service ├── .classpath ├── .gitignore ├── .project ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── sha │ │ │ └── eurekadiscoveryservice │ │ │ └── EurekaDiscoveryServiceApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── sha │ └── eurekadiscoveryservice │ └── EurekaDiscoveryServiceApplicationTests.java ├── microservice-course-management ├── .classpath ├── .gitignore ├── .project ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── sha │ │ │ └── microservicecoursemanagement │ │ │ ├── MicroserviceCourseManagementApplication.java │ │ │ ├── controller │ │ │ └── CourseController.java │ │ │ ├── intercomm │ │ │ └── UserClient.java │ │ │ ├── model │ │ │ ├── Course.java │ │ │ └── Transaction.java │ │ │ ├── repository │ │ │ ├── CourseRepository.java │ │ │ └── TransactionRepository.java │ │ │ └── service │ │ │ ├── CourseService.java │ │ │ └── CourseServiceImpl.java │ └── resources │ │ ├── application.properties │ │ └── db │ │ └── changelog │ │ ├── db.changelog-1.0.xml │ │ └── db.changelog-master.xml │ └── test │ └── java │ └── com │ └── sha │ └── microservicecoursemanagement │ └── MicroserviceCourseManagementApplicationTests.java ├── microservice-user-management ├── .classpath ├── .gitignore ├── .project ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── sha │ │ │ └── microserviceusermanagement │ │ │ ├── MicroserviceUserManagementApplication.java │ │ │ ├── config │ │ │ └── WebSecurityConfig.java │ │ │ ├── controller │ │ │ └── UserController.java │ │ │ ├── model │ │ │ ├── Role.java │ │ │ └── User.java │ │ │ ├── repository │ │ │ └── UserRepository.java │ │ │ └── service │ │ │ ├── UserDetailServiceImpl.java │ │ │ ├── UserService.java │ │ │ └── UserServiceImpl.java │ └── resources │ │ ├── application.properties │ │ └── db │ │ └── changelog │ │ ├── db.changelog-1.0.xml │ │ └── db.changelog-master.xml │ └── test │ └── java │ └── com │ └── sha │ └── microserviceusermanagement │ └── MicroserviceUserManagementApplicationTests.java └── zuul-gateway-service ├── .classpath ├── .gitignore ├── .project ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main ├── java │ └── com │ │ └── sha │ │ └── zuulgatewayservice │ │ └── ZuulGatewayServiceApplication.java └── resources │ └── application.properties └── test └── java └── com └── sha └── zuulgatewayservice └── ZuulGatewayServiceApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events.json 15 | speed-measure-plugin.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .c9/ 20 | *.launch 21 | *.sublime-workspace 22 | 23 | # IDE - VSCode 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # misc 32 | /.sass-cache 33 | /connect.lock 34 | /coverage 35 | /libpeerconnection.log 36 | npm-debug.log 37 | yarn-error.log 38 | testem.log 39 | /typings 40 | 41 | # System Files 42 | .DS_Store 43 | Thumbs.db 44 | 45 | # Server 46 | /.gradle 47 | /build/ 48 | /!gradle/wrapper/gradle-wrapper.jar 49 | /out/ 50 | /dist/ 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Course Enrollment Microservices, Spring Cloud, Spring Boot, Angular 8, MySQL, Hibernate, Liquibase 2 | 3 | The application structure is as follows. 4 | - **microservice-user-management** - Microservice implemented using Spring boot. [More info](microservice-user-management/README.md) 5 | - **microservice-course-management** - Microservice implemented using Spring boot. [More info](microservice-course-management/README.md) 6 | - **eureka-discovery-service** - Microservice implemented using Spring eureka. [More info](eureka-discovery-service/README.md) 7 | - **zuul-gateway-service** - Microservice implemented using Spring zuul. [More info](zuul-gateway-service/README.md) 8 | - **client-side** - A NodeJs application implemented using Angular 8. This consumes services hosted by server side. [More info](client-side/README.md) 9 | 10 | ### Build 11 | 12 | #### 1) Build Spring Boot microservices 13 | 14 | ``` 15 | $ cd microservice path 16 | $ gradlew bootJar 17 | $ gradlew bootRun 18 | ``` 19 | 20 | #### 2) Build and run client side application 21 | 22 | ``` 23 | $ cd client-side 24 | $ npm install 25 | $ ng serve 26 | ``` 27 | 28 | ### Access application using following URL 29 | 30 | ``` 31 | http://localhost:4200 32 | ``` 33 | -------------------------------------------------------------------------------- /client-side/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /client-side/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events.json 15 | speed-measure-plugin.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .c9/ 20 | *.launch 21 | .settings/ 22 | *.sublime-workspace 23 | 24 | # IDE - VSCode 25 | .vscode/* 26 | !.vscode/settings.json 27 | !.vscode/tasks.json 28 | !.vscode/launch.json 29 | !.vscode/extensions.json 30 | .history/* 31 | 32 | # misc 33 | /.sass-cache 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | npm-debug.log 38 | yarn-error.log 39 | testem.log 40 | /typings 41 | 42 | # System Files 43 | .DS_Store 44 | Thumbs.db 45 | -------------------------------------------------------------------------------- /client-side/README.md: -------------------------------------------------------------------------------- 1 | # ClientSide 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.0.1. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /client-side/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "client-side": { 7 | "projectType": "application", 8 | "schematics": {}, 9 | "root": "", 10 | "sourceRoot": "src", 11 | "prefix": "app", 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/client-side", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "tsconfig.app.json", 21 | "assets": [ 22 | "src/favicon.ico", 23 | "src/assets" 24 | ], 25 | "styles": [ 26 | "src/styles.css", 27 | "node_modules/bootstrap/dist/css/bootstrap.min.css", 28 | "src/assets/fonts/glyphicons/glyphicons.css" 29 | ], 30 | "scripts": [ 31 | "node_modules/jquery/dist/jquery.min.js", 32 | "node_modules/popper.js/dist/umd/popper.min.js", 33 | "node_modules/bootstrap/dist/js/bootstrap.min.js" 34 | ] 35 | }, 36 | "configurations": { 37 | "production": { 38 | "fileReplacements": [ 39 | { 40 | "replace": "src/environments/environment.ts", 41 | "with": "src/environments/environment.prod.ts" 42 | } 43 | ], 44 | "optimization": true, 45 | "outputHashing": "all", 46 | "sourceMap": false, 47 | "extractCss": true, 48 | "namedChunks": false, 49 | "aot": true, 50 | "extractLicenses": true, 51 | "vendorChunk": false, 52 | "buildOptimizer": true, 53 | "budgets": [ 54 | { 55 | "type": "initial", 56 | "maximumWarning": "2mb", 57 | "maximumError": "5mb" 58 | } 59 | ] 60 | } 61 | } 62 | }, 63 | "serve": { 64 | "builder": "@angular-devkit/build-angular:dev-server", 65 | "options": { 66 | "browserTarget": "client-side:build" 67 | }, 68 | "configurations": { 69 | "production": { 70 | "browserTarget": "client-side:build:production" 71 | } 72 | } 73 | }, 74 | "extract-i18n": { 75 | "builder": "@angular-devkit/build-angular:extract-i18n", 76 | "options": { 77 | "browserTarget": "client-side:build" 78 | } 79 | }, 80 | "test": { 81 | "builder": "@angular-devkit/build-angular:karma", 82 | "options": { 83 | "main": "src/test.ts", 84 | "polyfills": "src/polyfills.ts", 85 | "tsConfig": "tsconfig.spec.json", 86 | "karmaConfig": "karma.conf.js", 87 | "assets": [ 88 | "src/favicon.ico", 89 | "src/assets" 90 | ], 91 | "styles": [ 92 | "src/styles.css" 93 | ], 94 | "scripts": [] 95 | } 96 | }, 97 | "lint": { 98 | "builder": "@angular-devkit/build-angular:tslint", 99 | "options": { 100 | "tsConfig": [ 101 | "tsconfig.app.json", 102 | "tsconfig.spec.json", 103 | "e2e/tsconfig.json" 104 | ], 105 | "exclude": [ 106 | "**/node_modules/**" 107 | ] 108 | } 109 | }, 110 | "e2e": { 111 | "builder": "@angular-devkit/build-angular:protractor", 112 | "options": { 113 | "protractorConfig": "e2e/protractor.conf.js", 114 | "devServerTarget": "client-side:serve" 115 | }, 116 | "configurations": { 117 | "production": { 118 | "devServerTarget": "client-side:serve:production" 119 | } 120 | } 121 | } 122 | } 123 | }}, 124 | "defaultProject": "client-side" 125 | } -------------------------------------------------------------------------------- /client-side/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /client-side/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | 'browserName': 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /client-side/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to client-side!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /client-side/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /client-side/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /client-side/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/client-side'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /client-side/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client-side", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~8.0.0", 15 | "@angular/common": "~8.0.0", 16 | "@angular/compiler": "~8.0.0", 17 | "@angular/core": "~8.0.0", 18 | "@angular/forms": "~8.0.0", 19 | "@angular/platform-browser": "~8.0.0", 20 | "@angular/platform-browser-dynamic": "~8.0.0", 21 | "@angular/router": "~8.0.0", 22 | "bootstrap": "^4.3.1", 23 | "jquery": "^3.4.1", 24 | "popper.js": "^1.15.0", 25 | "rxjs": "~6.4.0", 26 | "tslib": "^1.9.0", 27 | "zone.js": "~0.9.1" 28 | }, 29 | "devDependencies": { 30 | "@angular-devkit/build-angular": "~0.800.0", 31 | "@angular/cli": "~8.0.1", 32 | "@angular/compiler-cli": "~8.0.0", 33 | "@angular/language-service": "~8.0.0", 34 | "@types/node": "~8.9.4", 35 | "@types/jasmine": "~3.3.8", 36 | "@types/jasminewd2": "~2.0.3", 37 | "codelyzer": "^5.0.0", 38 | "jasmine-core": "~3.4.0", 39 | "jasmine-spec-reporter": "~4.2.1", 40 | "karma": "~4.1.0", 41 | "karma-chrome-launcher": "~2.2.0", 42 | "karma-coverage-istanbul-reporter": "~2.0.1", 43 | "karma-jasmine": "~2.0.1", 44 | "karma-jasmine-html-reporter": "^1.4.0", 45 | "protractor": "~5.4.0", 46 | "ts-node": "~7.0.0", 47 | "tslint": "~5.15.0", 48 | "typescript": "~3.4.3" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /client-side/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import {HomeComponent} from './components/home/home.component'; 4 | import {LoginComponent} from './components/login/login.component'; 5 | import {RegisterComponent} from './components/register/register.component'; 6 | import {ProfileComponent} from './components/profile/profile.component'; 7 | import {DetailComponent} from './components/detail/detail.component'; 8 | 9 | const routes: Routes = [ 10 | {path: '', redirectTo:'home', pathMatch:'full'}, 11 | {path: 'home', component: HomeComponent}, 12 | {path: 'login', component: LoginComponent}, 13 | {path: 'register', component: RegisterComponent}, 14 | {path: 'profile', component: ProfileComponent}, 15 | {path: 'detail/:id', component: DetailComponent} 16 | ]; 17 | 18 | @NgModule({ 19 | imports: [RouterModule.forRoot(routes)], 20 | exports: [RouterModule] 21 | }) 22 | export class AppRoutingModule { } 23 | -------------------------------------------------------------------------------- /client-side/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/client-side/src/app/app.component.css -------------------------------------------------------------------------------- /client-side/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | Welcome to {{ title }}! 5 |

6 | 7 |
8 | 9 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /client-side/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | })); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.debugElement.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'client-side'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.debugElement.componentInstance; 26 | expect(app.title).toEqual('client-side'); 27 | }); 28 | 29 | it('should render title in a h1 tag', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.debugElement.nativeElement; 33 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to client-side!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /client-side/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import {UserService} from './services/user.service'; 3 | import {User} from './models/user'; 4 | import {Router} from '@angular/router'; 5 | 6 | @Component({ 7 | selector: 'app-root', 8 | templateUrl: './app.component.html', 9 | styleUrls: ['./app.component.css'] 10 | }) 11 | export class AppComponent { 12 | title = 'client-side'; 13 | currentUser: User; 14 | 15 | constructor(private userService: UserService, private router: Router) { 16 | //Call it observable because it can be changed from other page like login. 17 | this.userService.currentUser.subscribe(data => { 18 | this.currentUser = data; 19 | }); 20 | } 21 | 22 | logOut() { 23 | this.userService.logOut().subscribe(data => { 24 | this.router.navigate(['/login']); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /client-side/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | import { AppRoutingModule } from './app-routing.module'; 5 | import { AppComponent } from './app.component'; 6 | import { LoginComponent } from './components/login/login.component'; 7 | import { RegisterComponent } from './components/register/register.component'; 8 | import { ProfileComponent } from './components/profile/profile.component'; 9 | import { DetailComponent } from './components/detail/detail.component'; 10 | import { HomeComponent } from './components/home/home.component'; 11 | 12 | import {HttpClientModule} from '@angular/common/http'; 13 | import {FormsModule, ReactiveFormsModule} from '@angular/forms'; 14 | 15 | @NgModule({ 16 | declarations: [ 17 | AppComponent, 18 | LoginComponent, 19 | RegisterComponent, 20 | ProfileComponent, 21 | DetailComponent, 22 | HomeComponent 23 | ], 24 | imports: [ 25 | BrowserModule, 26 | AppRoutingModule, 27 | HttpClientModule, 28 | FormsModule, 29 | ReactiveFormsModule 30 | ], 31 | providers: [], 32 | bootstrap: [AppComponent] 33 | }) 34 | export class AppModule { } 35 | -------------------------------------------------------------------------------- /client-side/src/app/components/detail/detail.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/client-side/src/app/components/detail/detail.component.css -------------------------------------------------------------------------------- /client-side/src/app/components/detail/detail.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | Welcome to {{currentCourse.title}} 5 |

6 |
7 |
8 |
9 |
10 |
11 |
12 |

All Enrolled Students

13 |
14 |
15 |
16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
#Student Name
{{ind + 1}}{{item}}
32 |
33 |
34 |
35 |
-------------------------------------------------------------------------------- /client-side/src/app/components/detail/detail.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DetailComponent } from './detail.component'; 4 | 5 | describe('DetailComponent', () => { 6 | let component: DetailComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ DetailComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DetailComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client-side/src/app/components/detail/detail.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import {Course} from '../../models/course'; 3 | import {CourseService} from '../../services/course.service'; 4 | import {ActivatedRoute} from '@angular/router'; 5 | 6 | @Component({ 7 | selector: 'app-detail', 8 | templateUrl: './detail.component.html', 9 | styleUrls: ['./detail.component.css'] 10 | }) 11 | export class DetailComponent implements OnInit { 12 | 13 | courseId: number; 14 | currentCourse: Course; 15 | studentList: Array; 16 | 17 | constructor(private courseService: CourseService, private route: ActivatedRoute) { 18 | this.currentCourse = JSON.parse(localStorage.getItem('currentCourse')); 19 | } 20 | 21 | ngOnInit() { 22 | this.route.paramMap.subscribe(params => { 23 | if(params.has('id')) { 24 | this.courseId = Number.parseInt(params.get('id')); 25 | this.findStudentsOfCourse(); 26 | } 27 | }); 28 | } 29 | 30 | findStudentsOfCourse() { 31 | this.courseService.findStudentsOfCourse(this.courseId).subscribe(data => { 32 | this.studentList = data; 33 | }); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /client-side/src/app/components/home/home.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/client-side/src/app/components/home/home.component.css -------------------------------------------------------------------------------- /client-side/src/app/components/home/home.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | Error! {{errorMessage}} 4 |
5 |
6 | Successful! {{infoMessage}} 7 |
8 |
9 |
10 |
11 |
12 |
13 |

All Courses

14 |
15 |
16 |
17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 41 | 44 | 45 | 46 |
#TitleAuthorCategoryPublish DateEnrollDetail
{{ind + 1}}{{item.title}}{{item.author}}{{item.category}}{{item.publishDate | date:"MMM d, y"}} 39 | 40 | 42 | 43 |
47 |
48 |
49 |
50 |
51 | -------------------------------------------------------------------------------- /client-side/src/app/components/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | 5 | describe('HomeComponent', () => { 6 | let component: HomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ HomeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HomeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client-side/src/app/components/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import {CourseService} from '../../services/course.service'; 3 | import {UserService} from '../../services/user.service'; 4 | import {User} from '../../models/user'; 5 | import {Course} from '../../models/course'; 6 | import {Transaction} from '../../models/transaction'; 7 | import {Router} from '@angular/router'; 8 | import {DatePipe} from '@angular/common'; 9 | 10 | @Component({ 11 | selector: 'app-home', 12 | templateUrl: './home.component.html', 13 | styleUrls: ['./home.component.css'] 14 | }) 15 | export class HomeComponent implements OnInit { 16 | 17 | courseList: Array; 18 | errorMessage: string; 19 | infoMessage: string; 20 | currentUser: User; 21 | 22 | constructor(private userService: UserService, private courseService: CourseService, private router: Router) 23 | { 24 | this.currentUser = this.userService.currentUserValue; 25 | } 26 | 27 | ngOnInit() { 28 | this.findAllCourses(); 29 | } 30 | 31 | findAllCourses() { 32 | this.courseService.findAllCourses().subscribe(data => { 33 | this.courseList = data; 34 | }); 35 | } 36 | 37 | enroll(course: Course) { 38 | if(!this.currentUser){ 39 | this.errorMessage = "You should sign in to enroll a course"; 40 | return; 41 | } 42 | var transaction = new Transaction(); 43 | transaction.userId = this.currentUser.id; 44 | transaction.course = course; 45 | 46 | this.courseService.enroll(transaction).subscribe(data => { 47 | this.infoMessage = "Mission is completed."; 48 | }, err => { 49 | this.errorMessage = "Unexpected error occurred."; 50 | }); 51 | } 52 | 53 | detail(course: Course) { 54 | localStorage.setItem("currentCourse", JSON.stringify(course)); 55 | this.router.navigate(['/detail', course.id]); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /client-side/src/app/components/login/login.component.css: -------------------------------------------------------------------------------- 1 | label { 2 | display: block; 3 | margin-top: 10px; 4 | } 5 | 6 | .card-container.card { 7 | max-width: 350px !important; 8 | padding: 40px 40px; 9 | } 10 | 11 | .card { 12 | background-color: #f7f7f7; 13 | /* just in case there no content*/ 14 | padding: 20px 25px 30px; 15 | margin: 0 auto 25px; 16 | margin-top: 50px; 17 | /* shadows and rounded borders */ 18 | -moz-border-radius: 2px; 19 | -webkit-border-radius: 2px; 20 | border-radius: 2px; 21 | -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); 22 | -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); 23 | box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); 24 | } 25 | 26 | .profile-img-card { 27 | width: 96px; 28 | height: 96px; 29 | margin: 0 auto 10px; 30 | display: block; 31 | -moz-border-radius: 50%; 32 | -webkit-border-radius: 50%; 33 | border-radius: 50%; 34 | } -------------------------------------------------------------------------------- /client-side/src/app/components/login/login.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 8 |
9 | 10 | 11 |
12 | Username is required. 13 |
14 |
15 |
16 | 17 | 18 |
19 | Password is required. 20 |
21 |
22 | 23 |
24 | Create New Account! 25 |
26 |
-------------------------------------------------------------------------------- /client-side/src/app/components/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginComponent } from './login.component'; 4 | 5 | describe('LoginComponent', () => { 6 | let component: LoginComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoginComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoginComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client-side/src/app/components/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import {UserService} from '../../services/user.service'; 3 | import {User} from '../../models/user'; 4 | import {Router} from '@angular/router'; 5 | 6 | @Component({ 7 | selector: 'app-login', 8 | templateUrl: './login.component.html', 9 | styleUrls: ['./login.component.css'] 10 | }) 11 | export class LoginComponent implements OnInit { 12 | 13 | user: User = new User(); 14 | errorMessage: string; 15 | 16 | constructor(private userService: UserService, private router: Router) { } 17 | 18 | ngOnInit() { 19 | if(this.userService.currentUserValue){ 20 | this.router.navigate(['/home']); 21 | return; 22 | } 23 | } 24 | 25 | login(){ 26 | this.userService.login(this.user).subscribe(data => { 27 | this.router.navigate(['/profile']); 28 | }, err => { 29 | this.errorMessage = "Username or password is incorrect."; 30 | }); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /client-side/src/app/components/profile/profile.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/client-side/src/app/components/profile/profile.component.css -------------------------------------------------------------------------------- /client-side/src/app/components/profile/profile.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | {{currentUser.name}}, Welcome to my app. 5 |

6 |
7 | LogOut 8 |
9 |
10 |
11 |
12 |
13 |

All Enrolled Courses

14 |
15 |
16 |
17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
#Course TitleAuthorEnrollment Date
{{i + 1}}{{item.course.title}}{{item.course.author}}{{item.dateOfIssue | date:"MMM d, y, h:mm:ss a"}}
37 |
38 |
39 |
40 |
-------------------------------------------------------------------------------- /client-side/src/app/components/profile/profile.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ProfileComponent } from './profile.component'; 4 | 5 | describe('ProfileComponent', () => { 6 | let component: ProfileComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ProfileComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ProfileComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client-side/src/app/components/profile/profile.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import {CourseService} from '../../services/course.service'; 3 | import {UserService} from '../../services/user.service'; 4 | import {Transaction} from '../../models/transaction'; 5 | import {Router} from '@angular/router'; 6 | import {DatePipe} from '@angular/common'; 7 | import { User } from 'src/app/models/user'; 8 | 9 | @Component({ 10 | selector: 'app-profile', 11 | templateUrl: './profile.component.html', 12 | styleUrls: ['./profile.component.css'] 13 | }) 14 | export class ProfileComponent implements OnInit { 15 | 16 | currentUser: User; 17 | transactionList: Array; 18 | 19 | constructor(private userService: UserService, private courseService: CourseService, 20 | private router: Router) { 21 | this.currentUser = this.userService.currentUserValue; 22 | } 23 | 24 | ngOnInit() { 25 | if(!this.currentUser){ 26 | this.router.navigate(['/login']); 27 | return; 28 | } 29 | this.findTransactionsOfUser(); 30 | } 31 | 32 | findTransactionsOfUser() { 33 | this.courseService.findTransactionsOfUser(this.currentUser.id).subscribe(data => { 34 | this.transactionList = data; 35 | }); 36 | } 37 | 38 | logOut(){ 39 | this.userService.logOut().subscribe(data => { 40 | this.router.navigate(['/login']); 41 | }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /client-side/src/app/components/register/register.component.css: -------------------------------------------------------------------------------- 1 | label { 2 | display: block; 3 | margin-top: 10px; 4 | } 5 | 6 | .card-container.card { 7 | max-width: 350px !important; 8 | padding: 40px 40px; 9 | } 10 | 11 | .card { 12 | background-color: #f7f7f7; 13 | /* just in case there no content*/ 14 | padding: 20px 25px 30px; 15 | margin: 0 auto 25px; 16 | margin-top: 50px; 17 | /* shadows and rounded borders */ 18 | -moz-border-radius: 2px; 19 | -webkit-border-radius: 2px; 20 | border-radius: 2px; 21 | -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); 22 | -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); 23 | box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); 24 | } 25 | 26 | .profile-img-card { 27 | width: 96px; 28 | height: 96px; 29 | margin: 0 auto 10px; 30 | display: block; 31 | -moz-border-radius: 50%; 32 | -webkit-border-radius: 50%; 33 | border-radius: 50%; 34 | } -------------------------------------------------------------------------------- /client-side/src/app/components/register/register.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 8 |
9 | 10 | 11 |
12 | Full name is required. 13 |
14 |
15 |
16 | 17 | 18 |
19 | Username is required. 20 |
21 |
22 |
23 | 24 | 25 |
26 | Password is required. 27 |
28 |
29 | 30 |
31 | I have an Account! 32 |
33 |
-------------------------------------------------------------------------------- /client-side/src/app/components/register/register.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RegisterComponent } from './register.component'; 4 | 5 | describe('RegisterComponent', () => { 6 | let component: RegisterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ RegisterComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RegisterComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /client-side/src/app/components/register/register.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import {UserService} from '../../services/user.service'; 3 | import {User} from '../../models/user'; 4 | import {Router} from '@angular/router'; 5 | 6 | @Component({ 7 | selector: 'app-register', 8 | templateUrl: './register.component.html', 9 | styleUrls: ['./register.component.css'] 10 | }) 11 | export class RegisterComponent implements OnInit { 12 | 13 | user: User = new User(); 14 | errorMessage: string; 15 | 16 | constructor(private userService: UserService, private router: Router) { } 17 | 18 | ngOnInit() { 19 | if(this.userService.currentUserValue) { 20 | this.router.navigate(['/home']); 21 | return; 22 | } 23 | } 24 | 25 | register(){ 26 | this.userService.register(this.user).subscribe(data => { 27 | this.router.navigate(['/login']); 28 | }, err => { 29 | if(!err || err.status !== 409) { 30 | this.errorMessage = "Unexpected error occurred. Error : " + err; 31 | }else { 32 | this.errorMessage = "Username is already exist"; 33 | } 34 | }); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /client-side/src/app/models/course.ts: -------------------------------------------------------------------------------- 1 | export class Course { 2 | id: number; 3 | title: string=""; 4 | author: string=""; 5 | category: string=""; 6 | publishDate: any; 7 | } -------------------------------------------------------------------------------- /client-side/src/app/models/role.ts: -------------------------------------------------------------------------------- 1 | export enum Role { 2 | USER = 'USER', 3 | ADMIN = 'ADMIN', 4 | } -------------------------------------------------------------------------------- /client-side/src/app/models/transaction.ts: -------------------------------------------------------------------------------- 1 | import {Course} from './course'; 2 | 3 | export class Transaction { 4 | id: number; 5 | course: Course; 6 | userId: number; 7 | dateOfIssue: any; 8 | } -------------------------------------------------------------------------------- /client-side/src/app/models/user.ts: -------------------------------------------------------------------------------- 1 | import {Role} from './role'; 2 | export class User { 3 | id: number; 4 | username: string=""; 5 | password: string=""; 6 | name: string=""; 7 | role: Role; 8 | } -------------------------------------------------------------------------------- /client-side/src/app/services/course.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { CourseService } from './course.service'; 4 | 5 | describe('CourseService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: CourseService = TestBed.get(CourseService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client-side/src/app/services/course.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {Observable} from 'rxjs'; 4 | import {Course} from '../models/course'; 5 | import {Transaction} from '../models/transaction'; 6 | 7 | let API_URL = "http://localhost:8765/api/course/service/"; 8 | 9 | @Injectable({ 10 | providedIn: 'root' 11 | }) 12 | export class CourseService { 13 | 14 | constructor(private http: HttpClient) { } 15 | 16 | enroll(transaction: Transaction): Observable { 17 | return this.http.post(API_URL + 'enroll', JSON.stringify(transaction), 18 | {headers: {"Content-Type":"application/json; charset=UTF-8"}}); 19 | } 20 | 21 | findAllCourses(): Observable { 22 | return this.http.get(API_URL + "all",{headers: {"Content-Type":"application/json; charset=UTF-8"}}); 23 | } 24 | 25 | findTransactionsOfUser(userId: number): Observable { 26 | return this.http.get(API_URL + "user/" + userId, {headers: {"Content-Type":"application/json; charset=UTF-8"}}); 27 | } 28 | 29 | findStudentsOfCourse(courseId: number): Observable { 30 | return this.http.get(API_URL + "course/" + courseId, {headers: {"Content-Type":"application/json; charset=UTF-8"}}); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /client-side/src/app/services/user.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { UserService } from './user.service'; 4 | 5 | describe('UserService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: UserService = TestBed.get(UserService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /client-side/src/app/services/user.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import {HttpClient, HttpHeaders} from '@angular/common/http'; 3 | import {BehaviorSubject, Observable} from 'rxjs'; 4 | import {map} from 'rxjs/operators'; 5 | import {User} from '../models/user'; 6 | 7 | let API_URL = "http://localhost:8765/api/user/service/"; 8 | 9 | @Injectable({ 10 | providedIn: 'root' 11 | }) 12 | export class UserService { 13 | public currentUser: Observable; 14 | private currentUserSubject: BehaviorSubject; 15 | 16 | constructor(private http: HttpClient) { 17 | this.currentUserSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('currentUser'))); 18 | this.currentUser = this.currentUserSubject.asObservable(); 19 | } 20 | 21 | public get currentUserValue(): User { 22 | return this.currentUserSubject.value; 23 | } 24 | 25 | login(user: User): Observable { 26 | const headers = new HttpHeaders( 27 | user ? { 28 | authorization:'Basic ' + btoa(user.username + ':' + user.password) 29 | }:{} 30 | ); 31 | 32 | return this.http.get(API_URL + "login", {headers: headers}).pipe( 33 | map(response => { 34 | if(response) { 35 | localStorage.setItem('currentUser', JSON.stringify(response)); 36 | this.currentUserSubject.next(response); 37 | } 38 | return response; 39 | }) 40 | ); 41 | } 42 | 43 | logOut(): Observable { 44 | return this.http.post(API_URL + "logout", {}).pipe( 45 | map(response => { 46 | localStorage.removeItem('currentUser'); 47 | this.currentUserSubject.next(null); 48 | }) 49 | ); 50 | } 51 | 52 | register(user: User): Observable { 53 | return this.http.post(API_URL + "registration", JSON.stringify(user), 54 | {headers: {"Content-Type":"application/json; charset=UTF-8"}}); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /client-side/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/client-side/src/assets/.gitkeep -------------------------------------------------------------------------------- /client-side/src/assets/fonts/glyphicons/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/client-side/src/assets/fonts/glyphicons/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /client-side/src/assets/fonts/glyphicons/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/client-side/src/assets/fonts/glyphicons/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /client-side/src/assets/fonts/glyphicons/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/client-side/src/assets/fonts/glyphicons/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /client-side/src/assets/fonts/glyphicons/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/client-side/src/assets/fonts/glyphicons/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /client-side/src/assets/fonts/glyphicons/glyphicons.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Glyphicons Halflings'; 3 | 4 | src: url('./glyphicons-halflings-regular.eot'); 5 | src: url('./glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('./glyphicons-halflings-regular.woff2') format('woff2'), url('./glyphicons-halflings-regular.woff') format('woff'), url('./glyphicons-halflings-regular.ttf') format('truetype'), url('./glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); 6 | } 7 | .glyphicon { 8 | position: relative; 9 | top: 1px; 10 | display: inline-block; 11 | font-family: 'Glyphicons Halflings'; 12 | font-style: normal; 13 | font-weight: normal; 14 | line-height: 1; 15 | 16 | -webkit-font-smoothing: antialiased; 17 | -moz-osx-font-smoothing: grayscale; 18 | } 19 | .glyphicon-asterisk:before { 20 | content: "\2a"; 21 | } 22 | .glyphicon-plus:before { 23 | content: "\2b"; 24 | } 25 | .glyphicon-euro:before, 26 | .glyphicon-eur:before { 27 | content: "\20ac"; 28 | } 29 | .glyphicon-minus:before { 30 | content: "\2212"; 31 | } 32 | .glyphicon-cloud:before { 33 | content: "\2601"; 34 | } 35 | .glyphicon-envelope:before { 36 | content: "\2709"; 37 | } 38 | .glyphicon-pencil:before { 39 | content: "\270f"; 40 | } 41 | .glyphicon-glass:before { 42 | content: "\e001"; 43 | } 44 | .glyphicon-music:before { 45 | content: "\e002"; 46 | } 47 | .glyphicon-search:before { 48 | content: "\e003"; 49 | } 50 | .glyphicon-heart:before { 51 | content: "\e005"; 52 | } 53 | .glyphicon-star:before { 54 | content: "\e006"; 55 | } 56 | .glyphicon-star-empty:before { 57 | content: "\e007"; 58 | } 59 | .glyphicon-user:before { 60 | content: "\e008"; 61 | } 62 | .glyphicon-film:before { 63 | content: "\e009"; 64 | } 65 | .glyphicon-th-large:before { 66 | content: "\e010"; 67 | } 68 | .glyphicon-th:before { 69 | content: "\e011"; 70 | } 71 | .glyphicon-th-list:before { 72 | content: "\e012"; 73 | } 74 | .glyphicon-ok:before { 75 | content: "\e013"; 76 | } 77 | .glyphicon-remove:before { 78 | content: "\e014"; 79 | } 80 | .glyphicon-zoom-in:before { 81 | content: "\e015"; 82 | } 83 | .glyphicon-zoom-out:before { 84 | content: "\e016"; 85 | } 86 | .glyphicon-off:before { 87 | content: "\e017"; 88 | } 89 | .glyphicon-signal:before { 90 | content: "\e018"; 91 | } 92 | .glyphicon-cog:before { 93 | content: "\e019"; 94 | } 95 | .glyphicon-trash:before { 96 | content: "\e020"; 97 | } 98 | .glyphicon-home:before { 99 | content: "\e021"; 100 | } 101 | .glyphicon-file:before { 102 | content: "\e022"; 103 | } 104 | .glyphicon-time:before { 105 | content: "\e023"; 106 | } 107 | .glyphicon-road:before { 108 | content: "\e024"; 109 | } 110 | .glyphicon-download-alt:before { 111 | content: "\e025"; 112 | } 113 | .glyphicon-download:before { 114 | content: "\e026"; 115 | } 116 | .glyphicon-upload:before { 117 | content: "\e027"; 118 | } 119 | .glyphicon-inbox:before { 120 | content: "\e028"; 121 | } 122 | .glyphicon-play-circle:before { 123 | content: "\e029"; 124 | } 125 | .glyphicon-repeat:before { 126 | content: "\e030"; 127 | } 128 | .glyphicon-refresh:before { 129 | content: "\e031"; 130 | } 131 | .glyphicon-list-alt:before { 132 | content: "\e032"; 133 | } 134 | .glyphicon-lock:before { 135 | content: "\e033"; 136 | } 137 | .glyphicon-flag:before { 138 | content: "\e034"; 139 | } 140 | .glyphicon-headphones:before { 141 | content: "\e035"; 142 | } 143 | .glyphicon-volume-off:before { 144 | content: "\e036"; 145 | } 146 | .glyphicon-volume-down:before { 147 | content: "\e037"; 148 | } 149 | .glyphicon-volume-up:before { 150 | content: "\e038"; 151 | } 152 | .glyphicon-qrcode:before { 153 | content: "\e039"; 154 | } 155 | .glyphicon-barcode:before { 156 | content: "\e040"; 157 | } 158 | .glyphicon-tag:before { 159 | content: "\e041"; 160 | } 161 | .glyphicon-tags:before { 162 | content: "\e042"; 163 | } 164 | .glyphicon-book:before { 165 | content: "\e043"; 166 | } 167 | .glyphicon-bookmark:before { 168 | content: "\e044"; 169 | } 170 | .glyphicon-print:before { 171 | content: "\e045"; 172 | } 173 | .glyphicon-camera:before { 174 | content: "\e046"; 175 | } 176 | .glyphicon-font:before { 177 | content: "\e047"; 178 | } 179 | .glyphicon-bold:before { 180 | content: "\e048"; 181 | } 182 | .glyphicon-italic:before { 183 | content: "\e049"; 184 | } 185 | .glyphicon-text-height:before { 186 | content: "\e050"; 187 | } 188 | .glyphicon-text-width:before { 189 | content: "\e051"; 190 | } 191 | .glyphicon-align-left:before { 192 | content: "\e052"; 193 | } 194 | .glyphicon-align-center:before { 195 | content: "\e053"; 196 | } 197 | .glyphicon-align-right:before { 198 | content: "\e054"; 199 | } 200 | .glyphicon-align-justify:before { 201 | content: "\e055"; 202 | } 203 | .glyphicon-list:before { 204 | content: "\e056"; 205 | } 206 | .glyphicon-indent-left:before { 207 | content: "\e057"; 208 | } 209 | .glyphicon-indent-right:before { 210 | content: "\e058"; 211 | } 212 | .glyphicon-facetime-video:before { 213 | content: "\e059"; 214 | } 215 | .glyphicon-picture:before { 216 | content: "\e060"; 217 | } 218 | .glyphicon-map-marker:before { 219 | content: "\e062"; 220 | } 221 | .glyphicon-adjust:before { 222 | content: "\e063"; 223 | } 224 | .glyphicon-tint:before { 225 | content: "\e064"; 226 | } 227 | .glyphicon-edit:before { 228 | content: "\e065"; 229 | } 230 | .glyphicon-share:before { 231 | content: "\e066"; 232 | } 233 | .glyphicon-check:before { 234 | content: "\e067"; 235 | } 236 | .glyphicon-move:before { 237 | content: "\e068"; 238 | } 239 | .glyphicon-step-backward:before { 240 | content: "\e069"; 241 | } 242 | .glyphicon-fast-backward:before { 243 | content: "\e070"; 244 | } 245 | .glyphicon-backward:before { 246 | content: "\e071"; 247 | } 248 | .glyphicon-play:before { 249 | content: "\e072"; 250 | } 251 | .glyphicon-pause:before { 252 | content: "\e073"; 253 | } 254 | .glyphicon-stop:before { 255 | content: "\e074"; 256 | } 257 | .glyphicon-forward:before { 258 | content: "\e075"; 259 | } 260 | .glyphicon-fast-forward:before { 261 | content: "\e076"; 262 | } 263 | .glyphicon-step-forward:before { 264 | content: "\e077"; 265 | } 266 | .glyphicon-eject:before { 267 | content: "\e078"; 268 | } 269 | .glyphicon-chevron-left:before { 270 | content: "\e079"; 271 | } 272 | .glyphicon-chevron-right:before { 273 | content: "\e080"; 274 | } 275 | .glyphicon-plus-sign:before { 276 | content: "\e081"; 277 | } 278 | .glyphicon-minus-sign:before { 279 | content: "\e082"; 280 | } 281 | .glyphicon-remove-sign:before { 282 | content: "\e083"; 283 | } 284 | .glyphicon-ok-sign:before { 285 | content: "\e084"; 286 | } 287 | .glyphicon-question-sign:before { 288 | content: "\e085"; 289 | } 290 | .glyphicon-info-sign:before { 291 | content: "\e086"; 292 | } 293 | .glyphicon-screenshot:before { 294 | content: "\e087"; 295 | } 296 | .glyphicon-remove-circle:before { 297 | content: "\e088"; 298 | } 299 | .glyphicon-ok-circle:before { 300 | content: "\e089"; 301 | } 302 | .glyphicon-ban-circle:before { 303 | content: "\e090"; 304 | } 305 | .glyphicon-arrow-left:before { 306 | content: "\e091"; 307 | } 308 | .glyphicon-arrow-right:before { 309 | content: "\e092"; 310 | } 311 | .glyphicon-arrow-up:before { 312 | content: "\e093"; 313 | } 314 | .glyphicon-arrow-down:before { 315 | content: "\e094"; 316 | } 317 | .glyphicon-share-alt:before { 318 | content: "\e095"; 319 | } 320 | .glyphicon-resize-full:before { 321 | content: "\e096"; 322 | } 323 | .glyphicon-resize-small:before { 324 | content: "\e097"; 325 | } 326 | .glyphicon-exclamation-sign:before { 327 | content: "\e101"; 328 | } 329 | .glyphicon-gift:before { 330 | content: "\e102"; 331 | } 332 | .glyphicon-leaf:before { 333 | content: "\e103"; 334 | } 335 | .glyphicon-fire:before { 336 | content: "\e104"; 337 | } 338 | .glyphicon-eye-open:before { 339 | content: "\e105"; 340 | } 341 | .glyphicon-eye-close:before { 342 | content: "\e106"; 343 | } 344 | .glyphicon-warning-sign:before { 345 | content: "\e107"; 346 | } 347 | .glyphicon-plane:before { 348 | content: "\e108"; 349 | } 350 | .glyphicon-calendar:before { 351 | content: "\e109"; 352 | } 353 | .glyphicon-random:before { 354 | content: "\e110"; 355 | } 356 | .glyphicon-comment:before { 357 | content: "\e111"; 358 | } 359 | .glyphicon-magnet:before { 360 | content: "\e112"; 361 | } 362 | .glyphicon-chevron-up:before { 363 | content: "\e113"; 364 | } 365 | .glyphicon-chevron-down:before { 366 | content: "\e114"; 367 | } 368 | .glyphicon-retweet:before { 369 | content: "\e115"; 370 | } 371 | .glyphicon-shopping-cart:before { 372 | content: "\e116"; 373 | } 374 | .glyphicon-folder-close:before { 375 | content: "\e117"; 376 | } 377 | .glyphicon-folder-open:before { 378 | content: "\e118"; 379 | } 380 | .glyphicon-resize-vertical:before { 381 | content: "\e119"; 382 | } 383 | .glyphicon-resize-horizontal:before { 384 | content: "\e120"; 385 | } 386 | .glyphicon-hdd:before { 387 | content: "\e121"; 388 | } 389 | .glyphicon-bullhorn:before { 390 | content: "\e122"; 391 | } 392 | .glyphicon-bell:before { 393 | content: "\e123"; 394 | } 395 | .glyphicon-certificate:before { 396 | content: "\e124"; 397 | } 398 | .glyphicon-thumbs-up:before { 399 | content: "\e125"; 400 | } 401 | .glyphicon-thumbs-down:before { 402 | content: "\e126"; 403 | } 404 | .glyphicon-hand-right:before { 405 | content: "\e127"; 406 | } 407 | .glyphicon-hand-left:before { 408 | content: "\e128"; 409 | } 410 | .glyphicon-hand-up:before { 411 | content: "\e129"; 412 | } 413 | .glyphicon-hand-down:before { 414 | content: "\e130"; 415 | } 416 | .glyphicon-circle-arrow-right:before { 417 | content: "\e131"; 418 | } 419 | .glyphicon-circle-arrow-left:before { 420 | content: "\e132"; 421 | } 422 | .glyphicon-circle-arrow-up:before { 423 | content: "\e133"; 424 | } 425 | .glyphicon-circle-arrow-down:before { 426 | content: "\e134"; 427 | } 428 | .glyphicon-globe:before { 429 | content: "\e135"; 430 | } 431 | .glyphicon-wrench:before { 432 | content: "\e136"; 433 | } 434 | .glyphicon-tasks:before { 435 | content: "\e137"; 436 | } 437 | .glyphicon-filter:before { 438 | content: "\e138"; 439 | } 440 | .glyphicon-briefcase:before { 441 | content: "\e139"; 442 | } 443 | .glyphicon-fullscreen:before { 444 | content: "\e140"; 445 | } 446 | .glyphicon-dashboard:before { 447 | content: "\e141"; 448 | } 449 | .glyphicon-paperclip:before { 450 | content: "\e142"; 451 | } 452 | .glyphicon-heart-empty:before { 453 | content: "\e143"; 454 | } 455 | .glyphicon-link:before { 456 | content: "\e144"; 457 | } 458 | .glyphicon-phone:before { 459 | content: "\e145"; 460 | } 461 | .glyphicon-pushpin:before { 462 | content: "\e146"; 463 | } 464 | .glyphicon-usd:before { 465 | content: "\e148"; 466 | } 467 | .glyphicon-gbp:before { 468 | content: "\e149"; 469 | } 470 | .glyphicon-sort:before { 471 | content: "\e150"; 472 | } 473 | .glyphicon-sort-by-alphabet:before { 474 | content: "\e151"; 475 | } 476 | .glyphicon-sort-by-alphabet-alt:before { 477 | content: "\e152"; 478 | } 479 | .glyphicon-sort-by-order:before { 480 | content: "\e153"; 481 | } 482 | .glyphicon-sort-by-order-alt:before { 483 | content: "\e154"; 484 | } 485 | .glyphicon-sort-by-attributes:before { 486 | content: "\e155"; 487 | } 488 | .glyphicon-sort-by-attributes-alt:before { 489 | content: "\e156"; 490 | } 491 | .glyphicon-unchecked:before { 492 | content: "\e157"; 493 | } 494 | .glyphicon-expand:before { 495 | content: "\e158"; 496 | } 497 | .glyphicon-collapse-down:before { 498 | content: "\e159"; 499 | } 500 | .glyphicon-collapse-up:before { 501 | content: "\e160"; 502 | } 503 | .glyphicon-log-in:before { 504 | content: "\e161"; 505 | } 506 | .glyphicon-flash:before { 507 | content: "\e162"; 508 | } 509 | .glyphicon-log-out:before { 510 | content: "\e163"; 511 | } 512 | .glyphicon-new-window:before { 513 | content: "\e164"; 514 | } 515 | .glyphicon-record:before { 516 | content: "\e165"; 517 | } 518 | .glyphicon-save:before { 519 | content: "\e166"; 520 | } 521 | .glyphicon-open:before { 522 | content: "\e167"; 523 | } 524 | .glyphicon-saved:before { 525 | content: "\e168"; 526 | } 527 | .glyphicon-import:before { 528 | content: "\e169"; 529 | } 530 | .glyphicon-export:before { 531 | content: "\e170"; 532 | } 533 | .glyphicon-send:before { 534 | content: "\e171"; 535 | } 536 | .glyphicon-floppy-disk:before { 537 | content: "\e172"; 538 | } 539 | .glyphicon-floppy-saved:before { 540 | content: "\e173"; 541 | } 542 | .glyphicon-floppy-remove:before { 543 | content: "\e174"; 544 | } 545 | .glyphicon-floppy-save:before { 546 | content: "\e175"; 547 | } 548 | .glyphicon-floppy-open:before { 549 | content: "\e176"; 550 | } 551 | .glyphicon-credit-card:before { 552 | content: "\e177"; 553 | } 554 | .glyphicon-transfer:before { 555 | content: "\e178"; 556 | } 557 | .glyphicon-cutlery:before { 558 | content: "\e179"; 559 | } 560 | .glyphicon-header:before { 561 | content: "\e180"; 562 | } 563 | .glyphicon-compressed:before { 564 | content: "\e181"; 565 | } 566 | .glyphicon-earphone:before { 567 | content: "\e182"; 568 | } 569 | .glyphicon-phone-alt:before { 570 | content: "\e183"; 571 | } 572 | .glyphicon-tower:before { 573 | content: "\e184"; 574 | } 575 | .glyphicon-stats:before { 576 | content: "\e185"; 577 | } 578 | .glyphicon-sd-video:before { 579 | content: "\e186"; 580 | } 581 | .glyphicon-hd-video:before { 582 | content: "\e187"; 583 | } 584 | .glyphicon-subtitles:before { 585 | content: "\e188"; 586 | } 587 | .glyphicon-sound-stereo:before { 588 | content: "\e189"; 589 | } 590 | .glyphicon-sound-dolby:before { 591 | content: "\e190"; 592 | } 593 | .glyphicon-sound-5-1:before { 594 | content: "\e191"; 595 | } 596 | .glyphicon-sound-6-1:before { 597 | content: "\e192"; 598 | } 599 | .glyphicon-sound-7-1:before { 600 | content: "\e193"; 601 | } 602 | .glyphicon-copyright-mark:before { 603 | content: "\e194"; 604 | } 605 | .glyphicon-registration-mark:before { 606 | content: "\e195"; 607 | } 608 | .glyphicon-cloud-download:before { 609 | content: "\e197"; 610 | } 611 | .glyphicon-cloud-upload:before { 612 | content: "\e198"; 613 | } 614 | .glyphicon-tree-conifer:before { 615 | content: "\e199"; 616 | } 617 | .glyphicon-tree-deciduous:before { 618 | content: "\e200"; 619 | } 620 | .glyphicon-cd:before { 621 | content: "\e201"; 622 | } 623 | .glyphicon-save-file:before { 624 | content: "\e202"; 625 | } 626 | .glyphicon-open-file:before { 627 | content: "\e203"; 628 | } 629 | .glyphicon-level-up:before { 630 | content: "\e204"; 631 | } 632 | .glyphicon-copy:before { 633 | content: "\e205"; 634 | } 635 | .glyphicon-paste:before { 636 | content: "\e206"; 637 | } 638 | .glyphicon-alert:before { 639 | content: "\e209"; 640 | } 641 | .glyphicon-equalizer:before { 642 | content: "\e210"; 643 | } 644 | .glyphicon-king:before { 645 | content: "\e211"; 646 | } 647 | .glyphicon-queen:before { 648 | content: "\e212"; 649 | } 650 | .glyphicon-pawn:before { 651 | content: "\e213"; 652 | } 653 | .glyphicon-bishop:before { 654 | content: "\e214"; 655 | } 656 | .glyphicon-knight:before { 657 | content: "\e215"; 658 | } 659 | .glyphicon-baby-formula:before { 660 | content: "\e216"; 661 | } 662 | .glyphicon-tent:before { 663 | content: "\26fa"; 664 | } 665 | .glyphicon-blackboard:before { 666 | content: "\e218"; 667 | } 668 | .glyphicon-bed:before { 669 | content: "\e219"; 670 | } 671 | .glyphicon-apple:before { 672 | content: "\f8ff"; 673 | } 674 | .glyphicon-erase:before { 675 | content: "\e221"; 676 | } 677 | .glyphicon-hourglass:before { 678 | content: "\231b"; 679 | } 680 | .glyphicon-lamp:before { 681 | content: "\e223"; 682 | } 683 | .glyphicon-duplicate:before { 684 | content: "\e224"; 685 | } 686 | .glyphicon-piggy-bank:before { 687 | content: "\e225"; 688 | } 689 | .glyphicon-scissors:before { 690 | content: "\e226"; 691 | } 692 | .glyphicon-bitcoin:before { 693 | content: "\e227"; 694 | } 695 | .glyphicon-btc:before { 696 | content: "\e227"; 697 | } 698 | .glyphicon-xbt:before { 699 | content: "\e227"; 700 | } 701 | .glyphicon-yen:before { 702 | content: "\00a5"; 703 | } 704 | .glyphicon-jpy:before { 705 | content: "\00a5"; 706 | } 707 | .glyphicon-ruble:before { 708 | content: "\20bd"; 709 | } 710 | .glyphicon-rub:before { 711 | content: "\20bd"; 712 | } 713 | .glyphicon-scale:before { 714 | content: "\e230"; 715 | } 716 | .glyphicon-ice-lolly:before { 717 | content: "\e231"; 718 | } 719 | .glyphicon-ice-lolly-tasted:before { 720 | content: "\e232"; 721 | } 722 | .glyphicon-education:before { 723 | content: "\e233"; 724 | } 725 | .glyphicon-option-horizontal:before { 726 | content: "\e234"; 727 | } 728 | .glyphicon-option-vertical:before { 729 | content: "\e235"; 730 | } 731 | .glyphicon-menu-hamburger:before { 732 | content: "\e236"; 733 | } 734 | .glyphicon-modal-window:before { 735 | content: "\e237"; 736 | } 737 | .glyphicon-oil:before { 738 | content: "\e238"; 739 | } 740 | .glyphicon-grain:before { 741 | content: "\e239"; 742 | } 743 | .glyphicon-sunglasses:before { 744 | content: "\e240"; 745 | } 746 | .glyphicon-text-size:before { 747 | content: "\e241"; 748 | } 749 | .glyphicon-text-color:before { 750 | content: "\e242"; 751 | } 752 | .glyphicon-text-background:before { 753 | content: "\e243"; 754 | } 755 | .glyphicon-object-align-top:before { 756 | content: "\e244"; 757 | } 758 | .glyphicon-object-align-bottom:before { 759 | content: "\e245"; 760 | } 761 | .glyphicon-object-align-horizontal:before { 762 | content: "\e246"; 763 | } 764 | .glyphicon-object-align-left:before { 765 | content: "\e247"; 766 | } 767 | .glyphicon-object-align-vertical:before { 768 | content: "\e248"; 769 | } 770 | .glyphicon-object-align-right:before { 771 | content: "\e249"; 772 | } 773 | .glyphicon-triangle-right:before { 774 | content: "\e250"; 775 | } 776 | .glyphicon-triangle-left:before { 777 | content: "\e251"; 778 | } 779 | .glyphicon-triangle-bottom:before { 780 | content: "\e252"; 781 | } 782 | .glyphicon-triangle-top:before { 783 | content: "\e253"; 784 | } 785 | .glyphicon-console:before { 786 | content: "\e254"; 787 | } 788 | .glyphicon-superscript:before { 789 | content: "\e255"; 790 | } 791 | .glyphicon-subscript:before { 792 | content: "\e256"; 793 | } 794 | .glyphicon-menu-left:before { 795 | content: "\e257"; 796 | } 797 | .glyphicon-menu-right:before { 798 | content: "\e258"; 799 | } 800 | .glyphicon-menu-down:before { 801 | content: "\e259"; 802 | } 803 | .glyphicon-menu-up:before { 804 | content: "\e260"; 805 | } 806 | -------------------------------------------------------------------------------- /client-side/src/assets/fonts/prettify-angulario.css: -------------------------------------------------------------------------------- 1 | .prettyprint { 2 | white-space: pre-wrap; 3 | background: #F5F6F7; 4 | font-family: Monaco,"Lucida Console",monospace; 5 | color: #5C707A; 6 | width: auto; 7 | overflow: auto; 8 | position: relative; 9 | padding: 0; 10 | font-size: 13px; 11 | line-height: 24px; 12 | margin-bottom: 24px; 13 | border-radius: 4px; 14 | padding: 16px 32px 15 | } 16 | 17 | .prettyprint.linenums,.prettyprint[class^="linenums:"],.prettyprint[class*=" linenums:"] { 18 | padding: 0 19 | } 20 | 21 | .prettyprint.is-showcase { 22 | border: 4px solid #0273D4 23 | } 24 | 25 | .prettyprint code { 26 | background: none; 27 | font-size: 13px; 28 | padding: 0 29 | } 30 | 31 | .prettyprint ol { 32 | background: #F5F6F7; 33 | padding: 16px 32px 16px 56px; 34 | margin: 0; 35 | overflow: auto; 36 | font-size: 13px 37 | } 38 | 39 | .prettyprint ol li,.prettyprint .tag { 40 | color: #7a8b94; 41 | background: none; 42 | margin-bottom: 5px; 43 | line-height: normal; 44 | list-style-type: decimal; 45 | font-size: 12px 46 | } 47 | 48 | .prettyprint ol li:last-child { 49 | margin-bottom: 0 50 | } 51 | 52 | .prettyprint ol li code { 53 | background: none; 54 | font-size: 13px 55 | } 56 | 57 | .prettyprint .pnk,.prettyprint .blk { 58 | border-radius: 4px; 59 | padding: 2px 4px 60 | } 61 | 62 | .prettyprint .pnk { 63 | background: #CFD8DC; 64 | color: #5C707A 65 | } 66 | 67 | .prettyprint .blk { 68 | background: #E0E0E0 69 | } 70 | 71 | .prettyprint .otl { 72 | outline: 1px solid rgba(169,169,169,0.56) 73 | } 74 | 75 | .prettyprint .kwd { 76 | color: #D43669 77 | } 78 | 79 | .prettyprint .typ,.prettyprint .tag { 80 | color: #D43669 81 | } 82 | 83 | .prettyprint .str,.prettyprint .atv { 84 | color: #647f11 85 | } 86 | 87 | .prettyprint .atn { 88 | /*color: #647f11*/ 89 | color: #31708f 90 | } 91 | 92 | .prettyprint .com { 93 | color: #647f11 94 | } 95 | 96 | .prettyprint .lit { 97 | color: #647f11 98 | } 99 | 100 | .prettyprint .pun { 101 | color: #7a8b94 102 | } 103 | 104 | .prettyprint .pln { 105 | color: #5C707A 106 | /*color: #8a6d3b*/ 107 | } 108 | 109 | .prettyprint .dec { 110 | color: #647f11 111 | } 112 | 113 | @media print { 114 | .prettyprint { 115 | background: #F5F6F7; 116 | border: none; 117 | box-shadow: none 118 | } 119 | 120 | .prettyprint ol { 121 | background: #F5F6F7 122 | } 123 | 124 | .prettyprint .kwd { 125 | color: #D43669 126 | } 127 | 128 | .prettyprint .typ,.prettyprint .tag { 129 | color: #D43669 130 | } 131 | 132 | .prettyprint .str,.prettyprint .atv { 133 | color: #647f11 134 | } 135 | 136 | .prettyprint .atn { 137 | /*color: #647f11*/ 138 | color: #31708f 139 | } 140 | 141 | .prettyprint .com { 142 | color: #647f11 143 | } 144 | 145 | .prettyprint .lit { 146 | color: #647f11 147 | } 148 | 149 | .prettyprint .pun { 150 | color: #7a8b94 151 | } 152 | 153 | .prettyprint .pln { 154 | color: #5C707A 155 | } 156 | 157 | .prettyprint .dec { 158 | color: #647f11 159 | } 160 | } 161 | 162 | h1 .prettyprint,h2 .prettyprint,h3 .prettyprint,h4 .prettyprint { 163 | background: none; 164 | font-family: Monaco,"Lucida Console",monospace; 165 | color: #253238; 166 | overflow: hidden; 167 | position: relative; 168 | font-size: 15px; 169 | font-weight: 600; 170 | line-height: 24px; 171 | margin: 0; 172 | border: none; 173 | box-shadow: none; 174 | padding: 0 175 | } 176 | 177 | h1 .prettyprint code,h2 .prettyprint code,h3 .prettyprint code,h4 .prettyprint code { 178 | background: none; 179 | font-size: 15px; 180 | padding: 0 181 | } 182 | 183 | h1 .prettyprint .kwd,h2 .prettyprint .kwd,h3 .prettyprint .kwd,h4 .prettyprint .kwd { 184 | color: #253238 185 | } 186 | 187 | h1 .prettyprint .typ,h1 .prettyprint .tag,h2 .prettyprint .typ,h2 .prettyprint .tag,h3 .prettyprint .typ,h3 .prettyprint .tag,h4 .prettyprint .typ,h4 .prettyprint .tag { 188 | color: #B52E31 189 | } 190 | 191 | h1 .prettyprint .str,h1 .prettyprint .atv,h2 .prettyprint .str,h2 .prettyprint .atv,h3 .prettyprint .str,h3 .prettyprint .atv,h4 .prettyprint .str,h4 .prettyprint .atv { 192 | color: #9d8d00 193 | } 194 | 195 | h1 .prettyprint .atn,h2 .prettyprint .atn,h3 .prettyprint .atn,h4 .prettyprint .atn { 196 | color: #71a436 197 | } 198 | 199 | h1 .prettyprint .com,h2 .prettyprint .com,h3 .prettyprint .com,h4 .prettyprint .com { 200 | color: #AFBEC5 201 | } 202 | 203 | h1 .prettyprint .lit,h2 .prettyprint .lit,h3 .prettyprint .lit,h4 .prettyprint .lit { 204 | color: #9d8d00 205 | } 206 | 207 | h1 .prettyprint .pun,h2 .prettyprint .pun,h3 .prettyprint .pun,h4 .prettyprint .pun { 208 | color: #000 209 | } 210 | 211 | h1 .prettyprint .pln,h2 .prettyprint .pln,h3 .prettyprint .pln,h4 .prettyprint .pln { 212 | color: #000 213 | } 214 | 215 | h1 .prettyprint .dec,h2 .prettyprint .dec,h3 .prettyprint .dec,h4 .prettyprint .dec { 216 | color: #8762c6 217 | } 218 | -------------------------------------------------------------------------------- /client-side/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /client-side/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /client-side/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/client-side/src/favicon.ico -------------------------------------------------------------------------------- /client-side/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ClientSide 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /client-side/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /client-side/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags.ts'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /client-side/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | @import "~bootstrap/dist/css/bootstrap.css"; -------------------------------------------------------------------------------- /client-side/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /client-side/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "include": [ 8 | "src/**/*.ts" 9 | ], 10 | "exclude": [ 11 | "src/test.ts", 12 | "src/**/*.spec.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /client-side/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "esnext", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /client-side/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /client-side/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rules": { 4 | "array-type": false, 5 | "arrow-parens": false, 6 | "deprecation": { 7 | "severity": "warn" 8 | }, 9 | "component-class-suffix": true, 10 | "contextual-lifecycle": true, 11 | "directive-class-suffix": true, 12 | "directive-selector": [ 13 | true, 14 | "attribute", 15 | "app", 16 | "camelCase" 17 | ], 18 | "component-selector": [ 19 | true, 20 | "element", 21 | "app", 22 | "kebab-case" 23 | ], 24 | "import-blacklist": [ 25 | true, 26 | "rxjs/Rx" 27 | ], 28 | "interface-name": false, 29 | "max-classes-per-file": false, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-consecutive-blank-lines": false, 47 | "no-console": [ 48 | true, 49 | "debug", 50 | "info", 51 | "time", 52 | "timeEnd", 53 | "trace" 54 | ], 55 | "no-empty": false, 56 | "no-inferrable-types": [ 57 | true, 58 | "ignore-params" 59 | ], 60 | "no-non-null-assertion": true, 61 | "no-redundant-jsdoc": true, 62 | "no-switch-case-fall-through": true, 63 | "no-use-before-declare": true, 64 | "no-var-requires": false, 65 | "object-literal-key-quotes": [ 66 | true, 67 | "as-needed" 68 | ], 69 | "object-literal-sort-keys": false, 70 | "ordered-imports": false, 71 | "quotemark": [ 72 | true, 73 | "single" 74 | ], 75 | "trailing-comma": false, 76 | "no-conflicting-lifecycle": true, 77 | "no-host-metadata-property": true, 78 | "no-input-rename": true, 79 | "no-inputs-metadata-property": true, 80 | "no-output-native": true, 81 | "no-output-on-prefix": true, 82 | "no-output-rename": true, 83 | "no-outputs-metadata-property": true, 84 | "template-banana-in-box": true, 85 | "template-no-negated-async": true, 86 | "use-lifecycle-interface": true, 87 | "use-pipe-transform-interface": true 88 | }, 89 | "rulesDirectory": [ 90 | "codelyzer" 91 | ] 92 | } -------------------------------------------------------------------------------- /eureka-discovery-service/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /eureka-discovery-service/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/** 6 | !**/src/test/** 7 | 8 | ### STS ### 9 | .apt_generated 10 | .factorypath 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /eureka-discovery-service/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | eureka-discovery-service 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /eureka-discovery-service/README.md: -------------------------------------------------------------------------------- 1 | # Eureka-Service 2 | 3 | This project is a Spring Boot, MySQL, Hibernate and Liquibase project. 4 | 5 | ## Development server 6 | 7 | Run `Eureka-Service Main class` for a dev server. Navigate to `http://localhost:8761/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Build 10 | 11 | Run `gradlew clean build` 12 | 13 | java -Djava.security.egd=file:/dev/./urandom -jar app.jar 14 | -------------------------------------------------------------------------------- /eureka-discovery-service/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.1.6.RELEASE' 3 | id 'java' 4 | } 5 | 6 | apply plugin: 'io.spring.dependency-management' 7 | 8 | group = 'com.sha' 9 | version = '0.0.1-SNAPSHOT' 10 | sourceCompatibility = '1.8' 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | ext { 17 | set('springCloudVersion', "Greenwich.SR2") 18 | } 19 | 20 | dependencies { 21 | implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server' 22 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 23 | } 24 | 25 | dependencyManagement { 26 | imports { 27 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /eureka-discovery-service/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/eureka-discovery-service/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /eureka-discovery-service/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /eureka-discovery-service/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /eureka-discovery-service/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS="-Xmx64m" 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /eureka-discovery-service/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'eureka-discovery-service' 7 | -------------------------------------------------------------------------------- /eureka-discovery-service/src/main/java/com/sha/eurekadiscoveryservice/EurekaDiscoveryServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.sha.eurekadiscoveryservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaServer 9 | public class EurekaDiscoveryServiceApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(EurekaDiscoveryServiceApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /eureka-discovery-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8761 2 | 3 | #telling the server not to register himself in the service 4 | eureka.client.register-with-eureka=false 5 | #Eureka clients fetch the service registry (ServiceInstance: {URL, PORT, HOST}) from the Eureka server 6 | eureka.client.fetch-registry=true -------------------------------------------------------------------------------- /eureka-discovery-service/src/test/java/com/sha/eurekadiscoveryservice/EurekaDiscoveryServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sha.eurekadiscoveryservice; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class EurekaDiscoveryServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /microservice-course-management/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /microservice-course-management/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/** 6 | !**/src/test/** 7 | 8 | ### STS ### 9 | .apt_generated 10 | .factorypath 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /microservice-course-management/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | microservice-course-management 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /microservice-course-management/README.md: -------------------------------------------------------------------------------- 1 | # Course-Service 2 | 3 | This project is a Spring Boot, MySQL, Hibernate and Liquibase project. 4 | 5 | ## Development server 6 | 7 | Run `Course-Service Main class` for a dev server. Navigate to `http://localhost:8001/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Build 10 | 11 | Run `gradlew clean build` 12 | 13 | java -Djava.security.egd=file:/dev/./urandom -jar app.jar 14 | -------------------------------------------------------------------------------- /microservice-course-management/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.1.6.RELEASE' 3 | id 'java' 4 | } 5 | 6 | apply plugin: 'io.spring.dependency-management' 7 | 8 | group = 'com.sha' 9 | version = '0.0.1-SNAPSHOT' 10 | sourceCompatibility = '1.8' 11 | 12 | configurations { 13 | compileOnly { 14 | extendsFrom annotationProcessor 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | } 21 | 22 | ext { 23 | set('springCloudVersion', "Greenwich.SR2") 24 | } 25 | 26 | dependencies { 27 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 28 | implementation 'org.springframework.boot:spring-boot-starter-data-rest' 29 | implementation 'org.springframework.boot:spring-boot-starter-web' 30 | implementation 'org.liquibase:liquibase-core' 31 | implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' 32 | implementation 'org.springframework.cloud:spring-cloud-starter-openfeign' 33 | compileOnly 'org.projectlombok:lombok' 34 | runtimeOnly 'mysql:mysql-connector-java' 35 | annotationProcessor 'org.projectlombok:lombok' 36 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 37 | } 38 | 39 | dependencyManagement { 40 | imports { 41 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /microservice-course-management/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/microservice-course-management/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /microservice-course-management/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /microservice-course-management/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /microservice-course-management/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS="-Xmx64m" 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /microservice-course-management/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'microservice-course-management' 7 | -------------------------------------------------------------------------------- /microservice-course-management/src/main/java/com/sha/microservicecoursemanagement/MicroserviceCourseManagementApplication.java: -------------------------------------------------------------------------------- 1 | package com.sha.microservicecoursemanagement; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 | import org.springframework.cloud.openfeign.EnableFeignClients; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 9 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 10 | 11 | @SpringBootApplication 12 | @EnableDiscoveryClient 13 | @EnableFeignClients 14 | public class MicroserviceCourseManagementApplication { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(MicroserviceCourseManagementApplication.class, args); 18 | } 19 | 20 | @Bean 21 | public WebMvcConfigurer corsConfigurer() { 22 | return new WebMvcConfigurer() { 23 | @Override 24 | public void addCorsMappings(CorsRegistry registry) { 25 | registry.addMapping("/**").allowedOrigins("*"); 26 | } 27 | }; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /microservice-course-management/src/main/java/com/sha/microservicecoursemanagement/controller/CourseController.java: -------------------------------------------------------------------------------- 1 | package com.sha.microservicecoursemanagement.controller; 2 | 3 | import com.sha.microservicecoursemanagement.intercomm.UserClient; 4 | import com.sha.microservicecoursemanagement.model.Transaction; 5 | import com.sha.microservicecoursemanagement.service.CourseService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.cloud.client.discovery.DiscoveryClient; 9 | import org.springframework.core.env.Environment; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.util.CollectionUtils; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | import java.time.LocalDateTime; 16 | import java.util.List; 17 | import java.util.stream.Collectors; 18 | 19 | @RestController 20 | public class CourseController { 21 | 22 | @Autowired 23 | private UserClient userClient; 24 | 25 | @Autowired 26 | private CourseService courseService; 27 | 28 | @Autowired 29 | private DiscoveryClient discoveryClient; 30 | 31 | @Autowired 32 | private Environment env; 33 | 34 | @Value("${spring.application.name}") 35 | private String serviceId; 36 | 37 | @GetMapping("/service/port") 38 | public String getPort(){ 39 | return "Service is working at port : " + env.getProperty("local.server.port"); 40 | } 41 | 42 | @GetMapping("/service/instances") 43 | public ResponseEntity getInstances() { 44 | return ResponseEntity.ok(discoveryClient.getInstances(serviceId)); 45 | } 46 | 47 | @GetMapping("/service/user/{userId}") 48 | public ResponseEntity findTransactionsOfUser(@PathVariable Long userId){ 49 | return ResponseEntity.ok(courseService.findTransactionsOfUser(userId)); 50 | } 51 | 52 | @GetMapping("/service/all") 53 | public ResponseEntity findAllCourses(){ 54 | return ResponseEntity.ok(courseService.allCourses()); 55 | } 56 | 57 | @PostMapping("/service/enroll") 58 | public ResponseEntity saveTransaction(@RequestBody Transaction transaction) { 59 | transaction.setDateOfIssue(LocalDateTime.now()); 60 | transaction.setCourse(courseService.findCourseById(transaction.getCourse().getId())); 61 | return new ResponseEntity<>(courseService.saveTransaction(transaction), HttpStatus.CREATED); 62 | } 63 | 64 | @GetMapping("/service/course/{courseId}") 65 | public ResponseEntity findStudentsOfCourse(@PathVariable Long courseId){ 66 | List transactions = courseService.findTransactionsOfCourse(courseId); 67 | if(CollectionUtils.isEmpty(transactions)){ 68 | return ResponseEntity.notFound().build(); 69 | } 70 | List userIdList = transactions.parallelStream().map(t -> t.getUserId()).collect(Collectors.toList()); 71 | List students = userClient.getUserNames(userIdList); 72 | return ResponseEntity.ok(students); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /microservice-course-management/src/main/java/com/sha/microservicecoursemanagement/intercomm/UserClient.java: -------------------------------------------------------------------------------- 1 | package com.sha.microservicecoursemanagement.intercomm; 2 | 3 | import org.springframework.cloud.openfeign.FeignClient; 4 | import org.springframework.web.bind.annotation.RequestBody; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestMethod; 7 | 8 | import java.util.List; 9 | 10 | @FeignClient("user-service") 11 | public interface UserClient { 12 | 13 | @RequestMapping(method = RequestMethod.POST, value = "/service/names", consumes = "application/json") 14 | List getUserNames(@RequestBody List userIdList); 15 | } 16 | -------------------------------------------------------------------------------- /microservice-course-management/src/main/java/com/sha/microservicecoursemanagement/model/Course.java: -------------------------------------------------------------------------------- 1 | package com.sha.microservicecoursemanagement.model; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | import java.io.Serializable; 7 | import java.time.LocalDate; 8 | 9 | @Data 10 | @Entity 11 | @Table(name = "course") 12 | public class Course implements Serializable { 13 | 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) 16 | private Long id; 17 | 18 | @Column(name = "title") 19 | private String title; 20 | 21 | @Column(name = "author") 22 | private String author; 23 | 24 | @Column(name = "category") 25 | private String category; 26 | 27 | @Column(name = "publish_date") 28 | private LocalDate publishDate; 29 | } 30 | -------------------------------------------------------------------------------- /microservice-course-management/src/main/java/com/sha/microservicecoursemanagement/model/Transaction.java: -------------------------------------------------------------------------------- 1 | package com.sha.microservicecoursemanagement.model; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | import java.io.Serializable; 7 | import java.time.LocalDateTime; 8 | 9 | @Data 10 | @Entity 11 | @Table(name = "transaction") 12 | public class Transaction implements Serializable { 13 | 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) 16 | private Long id; 17 | 18 | @ManyToOne(fetch = FetchType.EAGER) 19 | @JoinColumn(name = "course_id", referencedColumnName = "id") 20 | private Course course; 21 | 22 | @Column(name = "user_id") 23 | private Long userId; 24 | 25 | @Column(name = "date_of_issue") 26 | private LocalDateTime dateOfIssue; 27 | } 28 | -------------------------------------------------------------------------------- /microservice-course-management/src/main/java/com/sha/microservicecoursemanagement/repository/CourseRepository.java: -------------------------------------------------------------------------------- 1 | package com.sha.microservicecoursemanagement.repository; 2 | 3 | import com.sha.microservicecoursemanagement.model.Course; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface CourseRepository extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /microservice-course-management/src/main/java/com/sha/microservicecoursemanagement/repository/TransactionRepository.java: -------------------------------------------------------------------------------- 1 | package com.sha.microservicecoursemanagement.repository; 2 | 3 | import com.sha.microservicecoursemanagement.model.Transaction; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.List; 7 | 8 | public interface TransactionRepository extends JpaRepository { 9 | 10 | List findAllByUserId(Long userId); 11 | 12 | List findAllByCourseId(Long courseId); 13 | } 14 | -------------------------------------------------------------------------------- /microservice-course-management/src/main/java/com/sha/microservicecoursemanagement/service/CourseService.java: -------------------------------------------------------------------------------- 1 | package com.sha.microservicecoursemanagement.service; 2 | 3 | import com.sha.microservicecoursemanagement.model.Course; 4 | import com.sha.microservicecoursemanagement.model.Transaction; 5 | 6 | import java.util.List; 7 | 8 | public interface CourseService { 9 | List allCourses(); 10 | 11 | Course findCourseById(Long courseId); 12 | 13 | List findTransactionsOfUser(Long userId); 14 | 15 | List findTransactionsOfCourse(Long courseId); 16 | 17 | Transaction saveTransaction(Transaction transaction); 18 | } 19 | -------------------------------------------------------------------------------- /microservice-course-management/src/main/java/com/sha/microservicecoursemanagement/service/CourseServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.sha.microservicecoursemanagement.service; 2 | 3 | import com.sha.microservicecoursemanagement.model.Course; 4 | import com.sha.microservicecoursemanagement.model.Transaction; 5 | import com.sha.microservicecoursemanagement.repository.CourseRepository; 6 | import com.sha.microservicecoursemanagement.repository.TransactionRepository; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.List; 11 | 12 | @Service 13 | public class CourseServiceImpl implements CourseService{ 14 | 15 | @Autowired 16 | private CourseRepository courseRepository; 17 | 18 | @Autowired 19 | private TransactionRepository transactionRepository; 20 | 21 | @Override 22 | public List allCourses() { 23 | return courseRepository.findAll(); 24 | } 25 | 26 | @Override 27 | public Course findCourseById(Long courseId) { 28 | return courseRepository.findById(courseId).orElse(null); 29 | } 30 | 31 | @Override 32 | public List findTransactionsOfUser(Long userId) { 33 | return transactionRepository.findAllByUserId(userId); 34 | } 35 | 36 | @Override 37 | public List findTransactionsOfCourse(Long courseId) { 38 | return transactionRepository.findAllByCourseId(courseId); 39 | } 40 | 41 | @Override 42 | public Transaction saveTransaction(Transaction transaction) { 43 | return transactionRepository.save(transaction); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /microservice-course-management/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=course-service 2 | server.port=8001 3 | 4 | #datasource 5 | spring.datasource.url=jdbc:mysql://localhost:3306/micro_course?useUnicode=true&useLegacyDatetimeCode=false&serverTimezone=UTC&createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useSSL=true 6 | #you should change them according to your credentials. 7 | spring.datasource.username=root 8 | spring.datasource.password=1234 9 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 10 | 11 | #disable hibernate auto ddl changes 12 | spring.jpa.hibernate.ddl-auto=none 13 | 14 | #liquibase 15 | spring.liquibase.change-log=classpath:/db/changelog/db.changelog-master.xml 16 | 17 | 18 | #eureka 19 | eureka.client.service-url.default-zone=http://localhost:8761/eureka/ 20 | #indicates the frequency the client sends heartbeats to server to indicate that it is alive. 21 | eureka.instance.lease-renewal-interval-in-seconds=30 22 | #indicates the duration the server waits since it received the last heartbeat before it can evict an instance from its registry. 23 | eureka.instance.lease-expiration-duration-in-seconds=90 24 | 25 | #load balancing 26 | ribbon.eureka.enabled=true -------------------------------------------------------------------------------- /microservice-course-management/src/main/resources/db/changelog/db.changelog-1.0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | CREATE TABLE course ( 13 | id BIGINT NOT NULL AUTO_INCREMENT, 14 | title VARCHAR(255) NOT NULL, 15 | author VARCHAR(255) NOT NULL, 16 | category VARCHAR(255), 17 | publish_date DATE, 18 | CONSTRAINT pk_id PRIMARY KEY (id) 19 | ); 20 | 21 | 22 | DROP TABLE course; 23 | 24 | 25 | 26 | 27 | CREATE TABLE transaction ( 28 | id BIGINT NOT NULL AUTO_INCREMENT, 29 | course_id BIGINT NOT NULL, 30 | user_id BIGINT NOT NULL, 31 | date_of_issue DATETIME, 32 | CONSTRAINT pk_id PRIMARY KEY (id), 33 | CONSTRAINT fk_tran_course FOREIGN KEY (course_id) REFERENCES course(id) ON DELETE CASCADE ON UPDATE CASCADE 34 | ); 35 | 36 | 37 | DROP TABLE transaction; 38 | 39 | 40 | 41 | 42 | INSERT INTO course (title, author, category, publish_date) VALUES('Microservices', 'Instructor 1', 'Programming', NOW()); 43 | INSERT INTO course (title, author, category, publish_date) VALUES('Java Programming', 'Instructor 2', 'Programming', NOW()); 44 | INSERT INTO course (title, author, category, publish_date) VALUES('Web Development', 'Instructor 3', 'Web', NOW()); 45 | INSERT INTO course (title, author, category, publish_date) VALUES('Mobile Application', 'Instructor 4', 'Mobile', NOW()); 46 | INSERT INTO course (title, author, category, publish_date) VALUES('Amazon Web Services', 'Instructor 5', 'Administration', NOW()); 47 | 48 | 49 | TRUNCATE TABLE course; 50 | 51 | 52 | -------------------------------------------------------------------------------- /microservice-course-management/src/main/resources/db/changelog/db.changelog-master.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /microservice-course-management/src/test/java/com/sha/microservicecoursemanagement/MicroserviceCourseManagementApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sha.microservicecoursemanagement; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class MicroserviceCourseManagementApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /microservice-user-management/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /microservice-user-management/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/** 6 | !**/src/test/** 7 | 8 | ### STS ### 9 | .apt_generated 10 | .factorypath 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /microservice-user-management/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | microservice-user-management 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /microservice-user-management/README.md: -------------------------------------------------------------------------------- 1 | # User-Service 2 | 3 | This project is a Spring Boot, MySQL, Hibernate and Liquibase project. 4 | 5 | ## Development server 6 | 7 | Run `User-Service Main class` for a dev server. Navigate to `http://localhost:8000/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Build 10 | 11 | Run `gradlew clean build` 12 | 13 | java -Djava.security.egd=file:/dev/./urandom -jar app.jar 14 | -------------------------------------------------------------------------------- /microservice-user-management/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.1.6.RELEASE' 3 | id 'java' 4 | } 5 | 6 | apply plugin: 'io.spring.dependency-management' 7 | 8 | group = 'com.sha' 9 | version = '0.0.1-SNAPSHOT' 10 | //You should change it according to your java version. 11 | sourceCompatibility = '1.8' 12 | 13 | configurations { 14 | compileOnly { 15 | extendsFrom annotationProcessor 16 | } 17 | } 18 | 19 | repositories { 20 | mavenCentral() 21 | } 22 | 23 | ext { 24 | set('springCloudVersion', "Greenwich.SR1") 25 | } 26 | 27 | dependencies { 28 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 29 | implementation 'org.springframework.boot:spring-boot-starter-data-rest' 30 | implementation 'org.springframework.boot:spring-boot-starter-security' 31 | implementation 'org.springframework.boot:spring-boot-starter-web' 32 | implementation 'org.liquibase:liquibase-core' 33 | implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' 34 | compileOnly 'org.projectlombok:lombok' 35 | runtimeOnly 'mysql:mysql-connector-java' 36 | annotationProcessor 'org.projectlombok:lombok' 37 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 38 | testImplementation 'org.springframework.security:spring-security-test' 39 | } 40 | 41 | dependencyManagement { 42 | imports { 43 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /microservice-user-management/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/microservice-user-management/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /microservice-user-management/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /microservice-user-management/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /microservice-user-management/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS="-Xmx64m" 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /microservice-user-management/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'microservice-user-management' 7 | -------------------------------------------------------------------------------- /microservice-user-management/src/main/java/com/sha/microserviceusermanagement/MicroserviceUserManagementApplication.java: -------------------------------------------------------------------------------- 1 | package com.sha.microserviceusermanagement; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 | 7 | @SpringBootApplication 8 | @EnableDiscoveryClient 9 | public class MicroserviceUserManagementApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(MicroserviceUserManagementApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /microservice-user-management/src/main/java/com/sha/microserviceusermanagement/config/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.sha.microserviceusermanagement.config; 2 | 3 | import com.sha.microserviceusermanagement.service.UserDetailServiceImpl; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 11 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 12 | import org.springframework.security.crypto.password.PasswordEncoder; 13 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher; 14 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 15 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 16 | 17 | @Configuration 18 | @EnableWebSecurity 19 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 20 | 21 | @Autowired 22 | private UserDetailServiceImpl userDetailsService; 23 | 24 | @Bean 25 | public PasswordEncoder passwordEncoder(){ 26 | return new BCryptPasswordEncoder(); 27 | } 28 | 29 | @Override 30 | protected void configure(HttpSecurity http) throws Exception { 31 | //Cross origin resource sharing 32 | http.cors().and() 33 | //starts authorizing configurations. 34 | .authorizeRequests() 35 | //ignoring the guest's urls... 36 | .antMatchers("/resources/**", "/error", "/service/**").permitAll() 37 | //authenticate all remaining URLs. 38 | .anyRequest().fullyAuthenticated() 39 | .and() 40 | .logout().permitAll() 41 | .logoutRequestMatcher(new AntPathRequestMatcher("/service/logout", "POST")) 42 | //login form 43 | .and() 44 | .formLogin().loginPage("/service/login").and() 45 | //enable basic header authentication. 46 | .httpBasic().and() 47 | //cross-side request forgery. 48 | .csrf().disable(); 49 | } 50 | 51 | @Override 52 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 53 | auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); 54 | } 55 | 56 | @Bean 57 | public WebMvcConfigurer corsConfigurer(){ 58 | return new WebMvcConfigurer() { 59 | @Override 60 | public void addCorsMappings(CorsRegistry registry) { 61 | registry.addMapping("/**").allowedOrigins("*"); 62 | } 63 | }; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /microservice-user-management/src/main/java/com/sha/microserviceusermanagement/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.sha.microserviceusermanagement.controller; 2 | 3 | import com.sha.microserviceusermanagement.model.Role; 4 | import com.sha.microserviceusermanagement.model.User; 5 | import com.sha.microserviceusermanagement.service.UserService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.cloud.client.discovery.DiscoveryClient; 9 | import org.springframework.core.env.Environment; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | import javax.servlet.http.HttpServletRequest; 15 | import java.security.Principal; 16 | import java.util.List; 17 | 18 | @RestController 19 | public class UserController { 20 | 21 | @Autowired 22 | private UserService userService; 23 | 24 | @Autowired 25 | private DiscoveryClient discoveryClient; 26 | 27 | @Autowired 28 | private Environment env; 29 | 30 | @Value("${spring.application.name}") 31 | private String serviceId; 32 | 33 | @GetMapping("/service/port") 34 | public String getPort(){ 35 | return "Service port number : " + env.getProperty("local.server.port"); 36 | } 37 | 38 | @GetMapping("/service/instances") 39 | public ResponseEntity getInstances(){ 40 | return new ResponseEntity<>(discoveryClient.getInstances(serviceId), HttpStatus.OK); 41 | } 42 | 43 | @GetMapping("/service/services") 44 | public ResponseEntity getServices(){ 45 | return new ResponseEntity<>(discoveryClient.getServices(), HttpStatus.OK); 46 | } 47 | 48 | @PostMapping("/service/registration") 49 | public ResponseEntity saveUser(@RequestBody User user){ 50 | if(userService.findByUsername(user.getUsername()) != null){ 51 | //Status Code: 409 52 | return new ResponseEntity<>(HttpStatus.CONFLICT); 53 | } 54 | //Default role = user 55 | user.setRole(Role.USER); 56 | return new ResponseEntity<>(userService.save(user), HttpStatus.CREATED); 57 | } 58 | 59 | @GetMapping("/service/login") 60 | public ResponseEntity getUser(Principal principal){ 61 | //Principal principal = request.getUserPrincipal(); 62 | if(principal == null || principal.getName() == null){ 63 | //This means; logout will be successful. login?logout 64 | return new ResponseEntity<>(HttpStatus.OK); 65 | } 66 | //username = principal.getName() 67 | return ResponseEntity.ok(userService.findByUsername(principal.getName())); 68 | } 69 | 70 | @PostMapping("/service/names") 71 | public ResponseEntity getNamesOfUsers(@RequestBody List idList){ 72 | return ResponseEntity.ok(userService.findUsers(idList)); 73 | } 74 | 75 | @GetMapping("/service/test") 76 | public ResponseEntity test(){ 77 | return ResponseEntity.ok("It is working..."); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /microservice-user-management/src/main/java/com/sha/microserviceusermanagement/model/Role.java: -------------------------------------------------------------------------------- 1 | package com.sha.microserviceusermanagement.model; 2 | 3 | public enum Role { 4 | USER, 5 | ADMIN 6 | } 7 | -------------------------------------------------------------------------------- /microservice-user-management/src/main/java/com/sha/microserviceusermanagement/model/User.java: -------------------------------------------------------------------------------- 1 | package com.sha.microserviceusermanagement.model; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.*; 6 | 7 | @Data 8 | @Entity 9 | @Table(name = "user") 10 | public class User { 11 | 12 | @Id 13 | //Generation Types: 14 | //Auto: Default one. It does not take any specific action. 15 | //Identity: Auto increment. 16 | //Sequence: Oracle or Posgresql creates variable to auto increment. 17 | //Table: Hibernate uses a database table to simulate a sequence. 18 | @GeneratedValue(strategy = GenerationType.IDENTITY) 19 | private Long id; 20 | 21 | @Column(name = "name") 22 | private String name; 23 | 24 | @Column(name = "username") 25 | private String username; 26 | 27 | @Column(name = "password") 28 | private String password; 29 | 30 | @Enumerated(value = EnumType.STRING) 31 | @Column(name = "role") 32 | private Role role; 33 | } 34 | -------------------------------------------------------------------------------- /microservice-user-management/src/main/java/com/sha/microserviceusermanagement/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.sha.microserviceusermanagement.repository; 2 | 3 | import com.sha.microserviceusermanagement.model.User; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | import org.springframework.data.repository.query.Param; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | public interface UserRepository extends JpaRepository { 12 | 13 | Optional findByUsername(String username); 14 | 15 | @Query("select u.name from User u where u.id in (:pIdList)") 16 | List findByIdList(@Param("pIdList") List idList); 17 | } 18 | -------------------------------------------------------------------------------- /microservice-user-management/src/main/java/com/sha/microserviceusermanagement/service/UserDetailServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.sha.microserviceusermanagement.service; 2 | 3 | import com.sha.microserviceusermanagement.model.User; 4 | import com.sha.microserviceusermanagement.repository.UserRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.core.GrantedAuthority; 7 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 8 | import org.springframework.security.core.userdetails.UserDetails; 9 | import org.springframework.security.core.userdetails.UserDetailsService; 10 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.HashSet; 14 | import java.util.Set; 15 | 16 | @Service 17 | public class UserDetailServiceImpl implements UserDetailsService { 18 | 19 | @Autowired 20 | private UserRepository userRepository; 21 | 22 | @Override 23 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 24 | User user = userRepository.findByUsername(username).orElse(null); 25 | if(user == null){ 26 | throw new UsernameNotFoundException(username); 27 | } 28 | Set authorities = new HashSet<>(); 29 | authorities.add(new SimpleGrantedAuthority(user.getRole().name())); 30 | 31 | return new org.springframework.security.core.userdetails.User(username, user.getPassword(), authorities); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /microservice-user-management/src/main/java/com/sha/microserviceusermanagement/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.sha.microserviceusermanagement.service; 2 | 3 | import com.sha.microserviceusermanagement.model.User; 4 | 5 | import java.util.List; 6 | 7 | public interface UserService { 8 | User save(User user); 9 | 10 | User findByUsername(String username); 11 | 12 | List findUsers(List idList); 13 | } 14 | -------------------------------------------------------------------------------- /microservice-user-management/src/main/java/com/sha/microserviceusermanagement/service/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.sha.microserviceusermanagement.service; 2 | 3 | import com.sha.microserviceusermanagement.model.User; 4 | import com.sha.microserviceusermanagement.repository.UserRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.crypto.password.PasswordEncoder; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.List; 10 | 11 | @Service 12 | public class UserServiceImpl implements UserService { 13 | 14 | @Autowired 15 | private UserRepository userRepository; 16 | 17 | //We will create bean for it in security config. 18 | @Autowired 19 | private PasswordEncoder passwordEncoder; 20 | 21 | @Override 22 | public User save(User user){ 23 | user.setPassword(passwordEncoder.encode(user.getPassword())); 24 | return userRepository.save(user); 25 | } 26 | 27 | @Override 28 | public User findByUsername(String username){ 29 | return userRepository.findByUsername(username).orElse(null); 30 | } 31 | 32 | @Override 33 | public List findUsers(List idList){ 34 | return userRepository.findByIdList(idList); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /microservice-user-management/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8000 2 | spring.application.name=user-service 3 | spring.datasource.url=jdbc:mysql://localhost:3306/micro_user?useUnicode=true&useLegacyDatetimeCode=false&serverTimezone=UTC&createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useSSL=false 4 | spring.datasource.username=root 5 | spring.datasource.password=1234 6 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 7 | 8 | #none,create,update,validate 9 | spring.jpa.hibernate.ddl-auto=none 10 | 11 | #liquibase 12 | spring.liquibase.change-log=classpath:/db/changelog/db.changelog-master.xml 13 | 14 | #eureka 15 | eureka.client.service-url.default-zone=http://localhost:8761/eureka/ 16 | #indicates the frequency the client sends heartbeat to server to indicate that it is alive. 17 | eureka.instance.lease-renewal-interval-in-seconds=30 18 | #indicates the duration the server waits since it received the last heartbeat before it can evict an instance from its registry 19 | eureka.instance.lease-expiration-duration-in-seconds=90 20 | 21 | #load balancing 22 | ribbon.eureka.enabled=true -------------------------------------------------------------------------------- /microservice-user-management/src/main/resources/db/changelog/db.changelog-1.0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | CREATE TABLE user ( 13 | id BIGINT NOT NULL AUTO_INCREMENT, 14 | username VARCHAR(255) NOT NULL, 15 | password VARCHAR(255) NOT NULL, 16 | name VARCHAR(255) NOT NULL, 17 | role VARCHAR(10) NOT NULL, 18 | CONSTRAINT pk_id PRIMARY KEY (id) 19 | ); 20 | 21 | 22 | DROP TABLE user; 23 | 24 | 25 | 26 | 27 | 28 | ALTER TABLE user ADD email varchar(255); 29 | 30 | 31 | ALTER TABLE user DROP COLUMN email; 32 | 33 | 34 | -------------------------------------------------------------------------------- /microservice-user-management/src/main/resources/db/changelog/db.changelog-master.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /microservice-user-management/src/test/java/com/sha/microserviceusermanagement/MicroserviceUserManagementApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sha.microserviceusermanagement; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class MicroserviceUserManagementApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /zuul-gateway-service/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /zuul-gateway-service/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/** 6 | !**/src/test/** 7 | 8 | ### STS ### 9 | .apt_generated 10 | .factorypath 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ 27 | 28 | ### VS Code ### 29 | .vscode/ 30 | -------------------------------------------------------------------------------- /zuul-gateway-service/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | zuul-gateway-service 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /zuul-gateway-service/README.md: -------------------------------------------------------------------------------- 1 | # Gateway-Service 2 | 3 | This project is a Spring Boot, Spring Zuul project. 4 | 5 | ## Development server 6 | 7 | Run `Gateway-Service Main class` for a dev server. Navigate to `http://localhost:8765/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Build 10 | 11 | Run `gradlew clean build` 12 | 13 | java -Djava.security.egd=file:/dev/./urandom -jar app.jar 14 | -------------------------------------------------------------------------------- /zuul-gateway-service/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.1.6.RELEASE' 3 | id 'java' 4 | } 5 | 6 | apply plugin: 'io.spring.dependency-management' 7 | 8 | group = 'com.sha' 9 | version = '0.0.1-SNAPSHOT' 10 | sourceCompatibility = '1.8' 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | ext { 17 | set('springCloudVersion', "Greenwich.SR2") 18 | } 19 | 20 | dependencies { 21 | implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' 22 | implementation 'org.springframework.cloud:spring-cloud-starter-netflix-zuul' 23 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 24 | } 25 | 26 | dependencyManagement { 27 | imports { 28 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /zuul-gateway-service/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/angular8-springboot-microservices/b804eed5df5e2c4c50d97c354fa42f0106a03ca9/zuul-gateway-service/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /zuul-gateway-service/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /zuul-gateway-service/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS='"-Xmx64m"' 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /zuul-gateway-service/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS="-Xmx64m" 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /zuul-gateway-service/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | rootProject.name = 'zuul-gateway-service' 7 | -------------------------------------------------------------------------------- /zuul-gateway-service/src/main/java/com/sha/zuulgatewayservice/ZuulGatewayServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.sha.zuulgatewayservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | import org.springframework.cloud.netflix.zuul.EnableZuulProxy; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 9 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 10 | 11 | @SpringBootApplication 12 | @EnableZuulProxy 13 | @EnableEurekaClient 14 | public class ZuulGatewayServiceApplication { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(ZuulGatewayServiceApplication.class, args); 18 | } 19 | 20 | @Bean 21 | public WebMvcConfigurer corsConfigurer() { 22 | return new WebMvcConfigurer() { 23 | @Override 24 | public void addCorsMappings(CorsRegistry registry) { 25 | registry.addMapping("/**").allowedOrigins("*"); 26 | } 27 | }; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /zuul-gateway-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=gateway-service 2 | server.port=8765 3 | 4 | zuul.ignored-headers=Access-Control-Allow-Credentials, Access-Control-Allow-Origin 5 | #Pass the headers from gateway to sub-microservices. 6 | zuul.sensitiveHeaders=Cookie,Set-Cookie 7 | 8 | zuul.prefix=/api 9 | #When path starts with /api/user/**, redirect it to user-service. 10 | zuul.routes.user.path=/user/** 11 | zuul.routes.user.serviceId=user-service 12 | #When path starts with /api/course/**, redirect it to course-service. 13 | zuul.routes.course.path=/course/** 14 | zuul.routes.course.serviceId=course-service 15 | 16 | #eureka 17 | eureka.client.service-url.default-zone=http://localhost:8761/eureka/ 18 | #indicates the frequency the client sends heartbeats to indicate that it is still alive. 19 | eureka.instance.lease-renewal-interval-in-seconds=30 20 | #indicates the duration the server waits since it received the last heartbeat before it can evict an instance from its registry 21 | eureka.instance.lease-expiration-duration-in-seconds=90 22 | 23 | #load balancing 24 | ribbon.eureka.enabled=true 25 | 26 | #timeout 27 | #this will help you load services eagerly. Otherwise for first time, we will get timeout exception. 28 | zuul.ribbon.eager-load.enabled=true 29 | #The read timeout in milliseconds. Default is 1000ms 30 | ribbon.ReadTimeout=60000 31 | #The Connection timeout in milliseconds. Default is 1000ms. 32 | ribbon.ConnectTimeout=10000 -------------------------------------------------------------------------------- /zuul-gateway-service/src/test/java/com/sha/zuulgatewayservice/ZuulGatewayServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sha.zuulgatewayservice; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ZuulGatewayServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------