├── .gitignore ├── README.md ├── client-side ├── .gitignore ├── README.md ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json └── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── models │ ├── transaction.js │ └── user.js │ ├── pages │ ├── detail │ │ └── detail.page.jsx │ ├── home │ │ └── home.page.jsx │ ├── login │ │ ├── login.page.css │ │ └── login.page.jsx │ ├── profile │ │ └── profile.page.jsx │ └── register │ │ ├── register.page.css │ │ └── register.page.jsx │ ├── serviceWorker.js │ └── services │ ├── course.service.js │ └── user.service.js ├── 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, React, 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 React. 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 | $ npm start 26 | ``` 27 | 28 | ### Access application using following URL 29 | 30 | ``` 31 | http://localhost:3000 32 | ``` 33 | -------------------------------------------------------------------------------- /client-side/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /client-side/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /client-side/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client-side", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@fortawesome/fontawesome-svg-core": "^1.2.18", 7 | "@fortawesome/free-solid-svg-icons": "^5.8.2", 8 | "@fortawesome/react-fontawesome": "^0.1.4", 9 | "axios": "^0.18.0", 10 | "bootstrap": "^4.3.1", 11 | "jquery": "^3.4.1", 12 | "popper.js": "^1.15.0", 13 | "react": "^16.8.6", 14 | "react-dom": "^16.8.6", 15 | "react-router-dom": "^5.0.0", 16 | "react-scripts": "3.0.1" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test", 22 | "eject": "react-scripts eject" 23 | }, 24 | "eslintConfig": { 25 | "extends": "react-app" 26 | }, 27 | "browserslist": { 28 | "production": [ 29 | ">0.2%", 30 | "not dead", 31 | "not op_mini all" 32 | ], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /client-side/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senolatac/react-springboot-microservices/727c78ecccb63509325a03f48b7f6624bde6341b/client-side/public/favicon.ico -------------------------------------------------------------------------------- /client-side/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 26 |
27 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /client-side/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /client-side/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 8vmin; 8 | pointer-events: none; 9 | } 10 | 11 | .App-header { 12 | background-color: #282c34; 13 | min-height: 100vh; 14 | display: flex; 15 | flex-direction: column; 16 | align-items: center; 17 | justify-content: center; 18 | font-size: calc(10px + 2vmin); 19 | color: white; 20 | } 21 | 22 | .App-link { 23 | color: #61dafb; 24 | } 25 | 26 | @keyframes App-logo-spin { 27 | from { 28 | transform: rotate(0deg); 29 | } 30 | to { 31 | transform: rotate(360deg); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /client-side/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | import {Router, Route, Link, Switch, Redirect} from 'react-router-dom'; 5 | import {createBrowserHistory} from 'history'; 6 | 7 | import HomePage from './pages/home/home.page'; 8 | import LoginPage from './pages/login/login.page'; 9 | import RegisterPage from './pages/register/register.page'; 10 | import ProfilePage from './pages/profile/profile.page'; 11 | import DetailPage from './pages/detail/detail.page'; 12 | 13 | import UserService from './services/user.service'; 14 | import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; 15 | import{ 16 | faUser, 17 | faUserPlus, 18 | faSignInAlt, 19 | faHome, 20 | faSignOutAlt 21 | } from '@fortawesome/free-solid-svg-icons'; 22 | import {User} from './models/user'; 23 | 24 | export default class App extends React.Component { 25 | constructor(props) { 26 | super(props); 27 | 28 | this.state = { 29 | history: createBrowserHistory(), 30 | currentUser: new User() 31 | }; 32 | } 33 | 34 | componentDidMount() { 35 | UserService.currentUser.subscribe(data => { 36 | this.setState({currentUser: data}); 37 | }); 38 | } 39 | 40 | logout() { 41 | UserService.logOut().then(data => { 42 | this.state.history.push('/home'); 43 | }, error => { 44 | this.setState({ 45 | errorMessage: "Unexpected error occurred." 46 | }); 47 | }); 48 | } 49 | 50 | render() { 51 | const {history, currentUser} = this.state; 52 | return ( 53 | 54 |
55 | {this.state.currentUser && 56 | 75 | } 76 | {!this.state.currentUser && 77 | 96 | } 97 |
98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 |
107 |
108 |
109 | ); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /client-side/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /client-side/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /client-side/src/index.js: -------------------------------------------------------------------------------- 1 | import 'bootstrap/dist/css/bootstrap.min.css'; 2 | import $ from 'jquery'; 3 | import Popper from 'popper.js'; 4 | import 'bootstrap/dist/js/bootstrap.bundle.min'; 5 | import React from 'react'; 6 | import ReactDOM from 'react-dom'; 7 | import './index.css'; 8 | import App from './App'; 9 | import * as serviceWorker from './serviceWorker'; 10 | 11 | ReactDOM.render(, document.getElementById('root')); 12 | 13 | // If you want your app to work offline and load faster, you can change 14 | // unregister() to register() below. Note this comes with some pitfalls. 15 | // Learn more about service workers: https://bit.ly/CRA-PWA 16 | serviceWorker.unregister(); 17 | -------------------------------------------------------------------------------- /client-side/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /client-side/src/models/transaction.js: -------------------------------------------------------------------------------- 1 | export class Transaction { 2 | constructor(userId, course, dateOfIssue, id){ 3 | this.userId = userId; 4 | this.course = course; 5 | this.dateOfIssue = dateOfIssue; 6 | this.id = id; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /client-side/src/models/user.js: -------------------------------------------------------------------------------- 1 | export class User { 2 | constructor(username, password, name, id){ 3 | this.username = username; 4 | this.password = password; 5 | this.name = name; 6 | this.id = id; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /client-side/src/pages/detail/detail.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CourseService from '../../services/course.service'; 3 | 4 | export default class DefaultPage extends React.Component { 5 | 6 | constructor(props) { 7 | super(props); 8 | 9 | this.state = { 10 | id: this.props.match.params.id, 11 | course: JSON.parse(localStorage.getItem('currentCourse')), 12 | students: [], 13 | }; 14 | } 15 | 16 | componentDidMount() { 17 | this.findStudentsOfCourse(); 18 | } 19 | 20 | findStudentsOfCourse() { 21 | CourseService.filterStudents(this.state.id).then(students => { 22 | this.setState({students: students.data}); 23 | }); 24 | } 25 | 26 | render() { 27 | const {students} = this.state; 28 | return ( 29 |
30 |
31 |

Course: {this.state.course.title}

32 |

Course Id: {this.state.id}

33 |
34 | {students.length && 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | {students.map((student, index) => 44 | 45 | 46 | 47 | 48 | )} 49 | 50 |
#Student Name
{index + 1}{student}
51 | } 52 |
53 | ); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /client-side/src/pages/home/home.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import UserService from '../../services/user.service'; 3 | import CourseService from '../../services/course.service'; 4 | import {User} from '../../models/user'; 5 | import {Transaction} from '../../models/transaction'; 6 | 7 | export default class HomePage extends React.Component { 8 | 9 | constructor(props) { 10 | super(props); 11 | this.state = { 12 | courses: [], 13 | errorMessage: '', 14 | infoMessage: '', 15 | currentUser: new User() 16 | }; 17 | } 18 | 19 | componentDidMount() { 20 | UserService.currentUser.subscribe(data => { 21 | this.setState({ 22 | currentUser: data 23 | }); 24 | }); 25 | 26 | this.getAllCourses(); 27 | } 28 | 29 | getAllCourses() { 30 | this.setState({ 31 | courses: {loading: true} 32 | }); 33 | 34 | CourseService.findAllCourses().then(courses => { 35 | this.setState({courses: courses.data}); 36 | }); 37 | } 38 | 39 | enroll(course) { 40 | if(!this.state.currentUser){ 41 | this.setState({errorMessage: 'To enroll a course, you should sign in.'}); 42 | return; 43 | } 44 | 45 | var transaction = new Transaction(this.state.currentUser.id, course); 46 | CourseService.createTransaction(transaction).then(data => { 47 | this.setState({infoMessage: 'You enrolled the course successfully.'}); 48 | }, error => { 49 | this.setState({errorMessage: 'Unexpected error occurred.'}); 50 | }); 51 | } 52 | 53 | detail(course) { 54 | localStorage.setItem('currentCourse', JSON.stringify(course)); 55 | this.props.history.push('/detail/' + course.id); 56 | } 57 | 58 | render() { 59 | const {courses, infoMessage, errorMessage} = this.state; 60 | return ( 61 |
62 | {infoMessage && 63 |
64 | Successfull! {infoMessage} 65 | 68 |
69 | } 70 | {errorMessage && 71 |
72 | Error! {errorMessage} 73 | 76 |
77 | } 78 | {courses.loading && Loading courses...} 79 | {courses.length && 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | {courses.map((course, index) => 92 | 93 | 94 | 95 | 96 | 99 | 102 | 103 | )} 104 | 105 |
#Course TitleAuthorDetailAction
{index + 1}{course.title}{course.author} 97 | 98 | 100 | 101 |
106 | } 107 |
108 | ); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /client-side/src/pages/login/login.page.css: -------------------------------------------------------------------------------- 1 | label{ 2 | display: block; 3 | margin-top: 10px; 4 | } 5 | 6 | .btn-link{ 7 | display: block; 8 | margin: auto; 9 | width: 100%; 10 | text-align: center; 11 | margin-top: 10px; 12 | color: cornflowerblue; 13 | } 14 | 15 | 16 | .card-container.card { 17 | max-width: 350px!important; 18 | padding: 40px 40px; 19 | } 20 | 21 | .btn { 22 | font-weight: 700; 23 | height: 36px; 24 | -moz-user-select: none; 25 | -webkit-user-select: none; 26 | user-select: none; 27 | cursor: default; 28 | } 29 | 30 | .card { 31 | background-color: #F7F7F7; 32 | /* just in case there no content*/ 33 | padding: 20px 25px 30px; 34 | margin: 0 auto 25px; 35 | margin-top: 50px; 36 | /* shadows and rounded borders */ 37 | -moz-border-radius: 2px; 38 | -webkit-border-radius: 2px; 39 | border-radius: 2px; 40 | -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); 41 | -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); 42 | box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); 43 | } 44 | 45 | .profile-img-card { 46 | width: 96px; 47 | height: 96px; 48 | margin: 0 auto 10px; 49 | display: block; 50 | -moz-border-radius: 50%; 51 | -webkit-border-radius: 50%; 52 | border-radius: 50%; 53 | } 54 | 55 | 56 | .form-signin #inputEmail, 57 | .form-signin #inputPassword { 58 | direction: ltr; 59 | height: 44px; 60 | font-size: 16px; 61 | } 62 | 63 | .form-signin input[type=email], 64 | .form-signin input[type=password], 65 | .form-signin input[type=text], 66 | .form-signin button { 67 | width: 100%; 68 | display: block; 69 | margin-bottom: 10px; 70 | z-index: 1; 71 | position: relative; 72 | -moz-box-sizing: border-box; 73 | -webkit-box-sizing: border-box; 74 | box-sizing: border-box; 75 | } 76 | 77 | .form-signin .form-control:focus { 78 | border-color: rgb(104, 145, 162); 79 | outline: 0; 80 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgb(104, 145, 162); 81 | box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgb(104, 145, 162); 82 | } 83 | 84 | .btn.btn-signin { 85 | /*background-color: #4d90fe; */ 86 | background-color: rgb(104, 145, 162); 87 | /* background-color: linear-gradient(rgb(104, 145, 162), rgb(12, 97, 33));*/ 88 | padding: 0px; 89 | font-weight: 700; 90 | font-size: 14px; 91 | height: 36px; 92 | -moz-border-radius: 3px; 93 | -webkit-border-radius: 3px; 94 | border-radius: 3px; 95 | border: none; 96 | -o-transition: all 0.218s; 97 | -moz-transition: all 0.218s; 98 | -webkit-transition: all 0.218s; 99 | transition: all 0.218s; 100 | } 101 | 102 | 103 | .btn.btn-signin:hover, 104 | .btn.btn-signin:active, 105 | .btn.btn-signin:focus { 106 | background-color: rgb(12, 97, 33); 107 | } 108 | -------------------------------------------------------------------------------- /client-side/src/pages/login/login.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import UserService from '../../services/user.service'; 3 | import {User} from '../../models/user'; 4 | import './login.page.css'; 5 | 6 | export default class LoginPage extends React.Component{ 7 | 8 | constructor(props) { 9 | super(props); 10 | 11 | if(UserService.currentUserValue) { 12 | this.props.history.push('/'); 13 | } 14 | 15 | this.state = { 16 | user: new User('',''), 17 | submitted: false, 18 | loading: false, 19 | errorMessage: '' 20 | }; 21 | } 22 | 23 | handleChange(e) { 24 | var {name, value} = e.target; 25 | var user = this.state.user; 26 | user[name] = value; 27 | this.setState({user: user}); 28 | } 29 | 30 | handleLogin(e) { 31 | e.preventDefault(); 32 | 33 | this.setState({submitted: true}); 34 | const {user} = this.state; 35 | 36 | if(!(user.username && user.password)){ 37 | return; 38 | } 39 | 40 | this.setState({loading: true}); 41 | UserService.login(user).then(data => { 42 | this.props.history.push("/home"); 43 | }, error => { 44 | this.setState({ 45 | errorMessage: "Username or password is not valid", 46 | loading: false 47 | }); 48 | }); 49 | } 50 | 51 | render() { 52 | const {user, submitted, loading, errorMessage} = this.state; 53 | return ( 54 |
55 |
56 | 57 | {errorMessage && 58 |
59 | Error! {errorMessage} 60 |
61 | } 62 |
this.handleLogin(e)}> 63 |
64 | 65 | this.handleChange(e)}/> 66 | {submitted && !user.username && 67 |
Username is required
68 | } 69 |
70 |
71 | 72 | this.handleChange(e)}/> 73 | {submitted && !user.password && 74 |
Password is required
75 | } 76 |
77 |
78 | 79 |
80 |
81 |
82 |
83 | ); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /client-side/src/pages/profile/profile.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import UserService from '../../services/user.service'; 3 | import CourseService from '../../services/course.service'; 4 | 5 | export default class ProfilePage extends React.Component { 6 | 7 | constructor(props) { 8 | super(props); 9 | 10 | if(!UserService.currentUserValue){ 11 | this.props.history.push('/'); 12 | return; 13 | } 14 | 15 | this.state = { 16 | user: UserService.currentUserValue, 17 | transactions: [] 18 | }; 19 | } 20 | 21 | componentDidMount() { 22 | this.setState({ 23 | transactions: {loading: true} 24 | }); 25 | const user = this.state.user; 26 | CourseService.filterTransactions(user.id).then(transactions => { 27 | this.setState({transactions: transactions.data}); 28 | }); 29 | } 30 | 31 | render() { 32 | const {transactions} = this.state; 33 | return ( 34 |
35 |
36 |

Hello, {this.state.user.name}

37 |
38 | {transactions.loading && Loading transactions...} 39 | {transactions.length && 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | {transactions.map((transaction, index) => 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | ) 60 | } 61 | 62 |
#Course TitleAuthorCategoryEnroll Date
{index + 1}{transaction.course.title}{transaction.course.author}{transaction.course.category}{transaction.dateOfIssue}
63 | } 64 |
65 | ); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /client-side/src/pages/register/register.page.css: -------------------------------------------------------------------------------- 1 | label{ 2 | display: block; 3 | margin-top: 10px; 4 | } 5 | 6 | .btn-link{ 7 | display: block; 8 | margin: auto; 9 | width: 100%; 10 | text-align: center; 11 | margin-top: 10px; 12 | color: cornflowerblue; 13 | } 14 | 15 | 16 | .card-container.card { 17 | max-width: 350px!important; 18 | padding: 40px 40px; 19 | } 20 | 21 | .btn { 22 | font-weight: 700; 23 | height: 36px; 24 | -moz-user-select: none; 25 | -webkit-user-select: none; 26 | user-select: none; 27 | cursor: default; 28 | } 29 | 30 | .card { 31 | background-color: #F7F7F7; 32 | /* just in case there no content*/ 33 | padding: 20px 25px 30px; 34 | margin: 0 auto 25px; 35 | margin-top: 50px; 36 | /* shadows and rounded borders */ 37 | -moz-border-radius: 2px; 38 | -webkit-border-radius: 2px; 39 | border-radius: 2px; 40 | -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); 41 | -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); 42 | box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); 43 | } 44 | 45 | .profile-img-card { 46 | width: 96px; 47 | height: 96px; 48 | margin: 0 auto 10px; 49 | display: block; 50 | -moz-border-radius: 50%; 51 | -webkit-border-radius: 50%; 52 | border-radius: 50%; 53 | } 54 | 55 | 56 | .form-signin #inputEmail, 57 | .form-signin #inputPassword { 58 | direction: ltr; 59 | height: 44px; 60 | font-size: 16px; 61 | } 62 | 63 | .form-signin input[type=email], 64 | .form-signin input[type=password], 65 | .form-signin input[type=text], 66 | .form-signin button { 67 | width: 100%; 68 | display: block; 69 | margin-bottom: 10px; 70 | z-index: 1; 71 | position: relative; 72 | -moz-box-sizing: border-box; 73 | -webkit-box-sizing: border-box; 74 | box-sizing: border-box; 75 | } 76 | 77 | .form-signin .form-control:focus { 78 | border-color: rgb(104, 145, 162); 79 | outline: 0; 80 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgb(104, 145, 162); 81 | box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgb(104, 145, 162); 82 | } 83 | 84 | .btn.btn-signin { 85 | /*background-color: #4d90fe; */ 86 | background-color: rgb(104, 145, 162); 87 | /* background-color: linear-gradient(rgb(104, 145, 162), rgb(12, 97, 33));*/ 88 | padding: 0px; 89 | font-weight: 700; 90 | font-size: 14px; 91 | height: 36px; 92 | -moz-border-radius: 3px; 93 | -webkit-border-radius: 3px; 94 | border-radius: 3px; 95 | border: none; 96 | -o-transition: all 0.218s; 97 | -moz-transition: all 0.218s; 98 | -webkit-transition: all 0.218s; 99 | transition: all 0.218s; 100 | } 101 | 102 | 103 | .btn.btn-signin:hover, 104 | .btn.btn-signin:active, 105 | .btn.btn-signin:focus { 106 | background-color: rgb(12, 97, 33); 107 | } 108 | -------------------------------------------------------------------------------- /client-side/src/pages/register/register.page.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import UserService from '../../services/user.service'; 3 | import {User} from '../../models/user'; 4 | import './register.page.css'; 5 | 6 | export default class RegisterPage extends React.Component { 7 | 8 | constructor(props) { 9 | super(props); 10 | 11 | if(UserService.currentUserValue) { 12 | this.props.history.push('/'); 13 | } 14 | 15 | this.state = { 16 | user: new User('','',''), 17 | submitted: false, 18 | loading: false, 19 | errorMessage: '' 20 | }; 21 | } 22 | 23 | handleChange(e) { 24 | var { name, value } = e.target; 25 | var user = this.state.user; 26 | user[name] = value; 27 | this.setState({user: user}); 28 | } 29 | 30 | handleRegister(e) { 31 | e.preventDefault(); 32 | this.setState({submitted: true}); 33 | const{user} = this.state; 34 | 35 | if(!(user.username && user.password && user.name)) { 36 | return; 37 | } 38 | 39 | this.setState({loading: true}); 40 | UserService.register(user).then(data => { 41 | this.props.history.push("/login"); 42 | }, error => { 43 | if(error.response.status === 409) { 44 | this.setState({ 45 | errorMessage: "Username is not available", 46 | loading: false 47 | }); 48 | }else { 49 | this.setState({ 50 | errorMessage: "Unexpected error occurred.", 51 | loading: false 52 | }); 53 | } 54 | }); 55 | } 56 | 57 | render() { 58 | const {user, submitted, loading, errorMessage} = this.state; 59 | return ( 60 |
61 |
62 | 63 | {errorMessage && 64 |
65 | Error! {errorMessage} 66 |
67 | } 68 |
this.handleRegister(e)}> 69 |
70 | 71 | this.handleChange(e)}/> 72 | {submitted && !user.name && 73 |
Full name is required
74 | } 75 |
76 |
77 | 78 | this.handleChange(e)}/> 79 | {submitted && !user.username && 80 |
Username is required
81 | } 82 |
83 |
84 | 85 | this.handleChange(e)}/> 86 | {submitted && !user.password && 87 |
Password is required
88 | } 89 |
90 |
91 | 92 |
93 |
94 |
95 |
96 | ); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /client-side/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /client-side/src/services/course.service.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | let API_URL = 'http://localhost:8765/api/course/service/'; 4 | 5 | class CourseService { 6 | createTransaction(transaction){ 7 | return axios.post(API_URL + 'enroll', JSON.stringify(transaction), 8 | {headers: {'Content-Type':'application/json; charset=UTF-8'}}); 9 | } 10 | 11 | filterTransactions(userId){ 12 | return axios.get(API_URL + 'user/'+ userId, 13 | {headers: {'Content-Type':'application/json; charset=UTF-8'}}); 14 | } 15 | 16 | filterStudents(courseId){ 17 | return axios.get(API_URL + 'course/' + courseId, 18 | {headers: {'Content-Type':'application/json; charset=UTF-8'}}); 19 | } 20 | 21 | findAllCourses(){ 22 | return axios.get(API_URL + 'all', 23 | {headers: {'Content-Type':'application/json; charset=UTF-8'}}); 24 | } 25 | } 26 | export default new CourseService(); 27 | -------------------------------------------------------------------------------- /client-side/src/services/user.service.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import {BehaviorSubject} from 'rxjs'; 3 | 4 | const API_URL = 'http://localhost:8765/api/user/service/'; 5 | 6 | const currentUserSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('currentUser'))); 7 | class UserService { 8 | get currentUserValue(){ 9 | return currentUserSubject.value; 10 | } 11 | 12 | get currentUser(){ 13 | return currentUserSubject.asObservable(); 14 | } 15 | 16 | login(user){ 17 | const headers = { 18 | authorization:'Basic ' + btoa(user.username + ':' + user.password) 19 | }; 20 | return axios.get(API_URL + 'login', {headers: headers}).then(response => { 21 | localStorage.setItem('currentUser', JSON.stringify(response.data)); 22 | currentUserSubject.next(response.data); 23 | }); 24 | } 25 | 26 | logOut(){ 27 | return axios.post(API_URL + 'logout', {}).then(response => { 28 | localStorage.removeItem('currentUser'); 29 | currentUserSubject.next(null); 30 | }) 31 | } 32 | 33 | register(user){ 34 | return axios.post(API_URL + 'registration', JSON.stringify(user), 35 | {headers: {'Content-Type':'application/json; charset=UTF-8'}}); 36 | } 37 | 38 | } 39 | 40 | export default new UserService(); 41 | -------------------------------------------------------------------------------- /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/react-springboot-microservices/727c78ecccb63509325a03f48b7f6624bde6341b/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/react-springboot-microservices/727c78ecccb63509325a03f48b7f6624bde6341b/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/react-springboot-microservices/727c78ecccb63509325a03f48b7f6624bde6341b/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/react-springboot-microservices/727c78ecccb63509325a03f48b7f6624bde6341b/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 | --------------------------------------------------------------------------------