Skip to content

Commit ee9290e

Browse files
DoRmAmMu1997codex
andcommitted
Improve Spring Boot MySQL application structure
Co-authored-by: Codex <codex@openai.com>
1 parent d4eb8e0 commit ee9290e

38 files changed

Lines changed: 1314 additions & 491 deletions

.github/workflows/ci.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Java CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Check out repository
15+
uses: actions/checkout@v4
16+
17+
- name: Set up Java 11
18+
uses: actions/setup-java@v4
19+
with:
20+
distribution: temurin
21+
java-version: "11"
22+
cache: maven
23+
24+
- name: Run tests
25+
run: ./mvnw test

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
target/
2+
*.class
3+
4+
.idea/
5+
.vscode/
6+
*.iml
7+
8+
.classpath
9+
.project
10+
.settings/
11+
12+
*.log
13+
.env
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2+
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

README.md

Lines changed: 171 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,178 @@
1-
# My-SpringBoot-MySQL-Application
1+
# My Spring Boot MySQL Application
22

3-
# Read Me First
4-
The following was discovered as part of building this project:
3+
This is an educational Spring Boot REST API for managing employees,
4+
departments, addresses, profiles, and simple login/logout state. The app uses
5+
Spring Web, Spring Data JPA, Bean Validation, and MySQL for local development.
56

6-
* The original package name 'com.hemant.db.springboot-mysql' is invalid and this project uses 'com.hemant.db.springbootmysql' instead.
7+
## Tech Stack
78

8-
# Getting Started
9+
- Java 11
10+
- Spring Boot 2.7.x
11+
- Spring Web
12+
- Spring Data JPA
13+
- MySQL Connector/J
14+
- H2 for automated tests
15+
- Maven Wrapper
916

10-
### Reference Documentation
11-
For further reference, please consider the following sections:
17+
## Project Structure
1218

13-
* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
14-
* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.5.2/maven-plugin/reference/html/)
15-
* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.5.2/maven-plugin/reference/html/#build-image)
16-
* [Spring Web](https://docs.spring.io/spring-boot/docs/2.5.2/reference/htmlsingle/#boot-features-developing-web-applications)
17-
* [Spring Data JPA](https://docs.spring.io/spring-boot/docs/2.5.2/reference/htmlsingle/#boot-features-jpa-and-spring-data)
18-
* [JDBC API](https://docs.spring.io/spring-boot/docs/2.5.2/reference/htmlsingle/#boot-features-sql)
19+
```text
20+
.
21+
|-- pom.xml
22+
|-- mvnw / mvnw.cmd
23+
|-- src/
24+
| |-- main/
25+
| | |-- java/com/hemant/db/
26+
| | | |-- SpringbootMysqlApplication.java
27+
| | | |-- exception/
28+
| | | |-- model/
29+
| | | |-- repository/
30+
| | | |-- resource/
31+
| | | `-- service/
32+
| | `-- resources/application.yml
33+
| `-- test/
34+
| |-- java/com/hemant/db/
35+
| `-- resources/application-test.yml
36+
`-- .github/workflows/ci.yml
37+
```
1938

20-
### Guides
21-
The following guides illustrate how to use some features concretely:
39+
### Main Packages
2240

23-
* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)
24-
* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/)
25-
* [Building REST services with Spring](https://spring.io/guides/tutorials/bookmarks/)
26-
* [Accessing Data with JPA](https://spring.io/guides/gs/accessing-data-jpa/)
27-
* [Accessing Relational Data using JDBC with Spring](https://spring.io/guides/gs/relational-data-access/)
28-
* [Managing Transactions](https://spring.io/guides/gs/managing-transactions/)
41+
`model` contains the JPA entities that map to database tables. Examples:
42+
`Employee`, `Department`, `Address`, and `Profile`.
43+
44+
`repository` contains Spring Data JPA repositories. These interfaces provide
45+
database access methods such as `findByEmail`, `findByCity`, and `findByName`.
46+
47+
`service` contains business logic. Controllers call services instead of talking
48+
directly to repositories, which keeps request handling and application rules
49+
separate.
50+
51+
`resource` contains REST controllers. These preserve the original `/rest/...`
52+
routes while delegating work to services.
53+
54+
`exception` contains shared API error handling. Missing records, duplicate
55+
records, bad requests, and validation failures return consistent JSON error
56+
responses.
57+
58+
## Configuration
59+
60+
The app reads database settings from environment variables with local defaults:
61+
62+
| Variable | Default |
63+
| --- | --- |
64+
| `MYSQL_URL` | `jdbc:mysql://localhost:3306/employee_db` |
65+
| `MYSQL_USERNAME` | `root` |
66+
| `MYSQL_PASSWORD` | empty |
67+
| `JPA_DDL_AUTO` | `update` |
68+
| `JPA_SHOW_SQL` | `true` |
69+
70+
Example PowerShell setup:
71+
72+
```powershell
73+
$env:MYSQL_URL="jdbc:mysql://localhost:3306/employee_db"
74+
$env:MYSQL_USERNAME="root"
75+
$env:MYSQL_PASSWORD="your-password"
76+
```
77+
78+
## Run Locally
79+
80+
Start MySQL and create the database:
81+
82+
```sql
83+
CREATE DATABASE employee_db;
84+
```
85+
86+
Then run the application:
87+
88+
```powershell
89+
.\mvnw.cmd spring-boot:run
90+
```
91+
92+
On macOS/Linux:
93+
94+
```bash
95+
./mvnw spring-boot:run
96+
```
97+
98+
The API starts on the default Spring Boot port:
99+
100+
```text
101+
http://localhost:8080
102+
```
103+
104+
## API Overview
105+
106+
The existing route style is preserved.
107+
108+
### Employees
109+
110+
- `GET /rest/Employee/all`
111+
- `POST /rest/Employee/insert`
112+
- `GET /rest/Employee/findbyname?name=...`
113+
- `GET /rest/Employee/findbydesignation?designation=...`
114+
- `POST /rest/Employee/updatedesignation?Id=...&designation=...`
115+
- `POST /rest/Employee/updatemobile?Id=...&mobile=...`
116+
- `POST /rest/Employee/updatepassword?Id=...&password=...`
117+
- `DELETE /rest/Employee/delete?Id=...`
118+
119+
### Departments
120+
121+
- `GET /rest/Department/all`
122+
- `POST /rest/Department/insert`
123+
- `GET /rest/Department/findbyname?name=...`
124+
- `GET /rest/Department/findbyaddress?address=...`
125+
- `POST /rest/Department/updatefloor?Id=...&floor=...`
126+
- `POST /rest/Department/updateaddress?Id=...&address=...`
127+
- `DELETE /rest/Department/delete?Id=...`
128+
129+
### Addresses
130+
131+
- `GET /rest/Address/all`
132+
- `POST /rest/Address/insert`
133+
- `GET /rest/Address/findbycity?city=...`
134+
- `GET /rest/Address/findbystate?state=...`
135+
- `POST /rest/Address/updateaddress?...`
136+
- `DELETE /rest/Address/delete?Id=...`
137+
138+
### Profiles
139+
140+
- `GET /rest/Profile/all`
141+
- `POST /rest/Profile/insert`
142+
- `GET /rest/Profile/findbygender?gender=...`
143+
- `GET /rest/Profile/findbyhobbies?hobbies=...`
144+
- `POST /rest/Profile/updatehobbies?Id=...&hobbies=...`
145+
- `DELETE /rest/Profile/delete?Id=...`
146+
147+
### Login
148+
149+
- `GET /rest/Login/findbyemail?email=...`
150+
- `POST /rest/Login/login?email=...&password=...`
151+
- `POST /rest/Login/logout?email=...`
152+
153+
## Testing
154+
155+
Tests use H2 in MySQL compatibility mode, so they do not require a local MySQL
156+
server.
157+
158+
```powershell
159+
.\mvnw.cmd test
160+
```
161+
162+
On macOS/Linux:
163+
164+
```bash
165+
./mvnw test
166+
```
167+
168+
The GitHub Actions workflow also runs the Maven test suite on Java 11 for pushes
169+
to `main` and pull requests.
170+
171+
## Notes
172+
173+
- Passwords are accepted for create/update/login operations but are hidden from
174+
JSON responses.
175+
- This project intentionally keeps the original route naming style to avoid
176+
breaking existing clients.
177+
- Authentication is educational only. It stores a login status and plain
178+
password values, so it should not be used as-is for production security.

mvnw

100644100755
File mode changed.

pom.xml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>org.springframework.boot</groupId>
77
<artifactId>spring-boot-starter-parent</artifactId>
8-
<version>2.5.2</version>
8+
<version>2.7.18</version>
99
<relativePath/> <!-- lookup parent from repository -->
1010
</parent>
1111
<groupId>com.hemant.db</groupId>
@@ -35,14 +35,19 @@
3535
<scope>test</scope>
3636
</dependency>
3737
<dependency>
38-
<groupId>mysql</groupId>
39-
<artifactId>mysql-connector-java</artifactId>
40-
<version>8.0.25</version><!--$NO-MVN-MAN-VER$-->
38+
<groupId>com.mysql</groupId>
39+
<artifactId>mysql-connector-j</artifactId>
40+
<scope>runtime</scope>
4141
</dependency>
4242
<dependency>
4343
<groupId>org.springframework.boot</groupId>
4444
<artifactId>spring-boot-starter-validation</artifactId>
4545
</dependency>
46+
<dependency>
47+
<groupId>com.h2database</groupId>
48+
<artifactId>h2</artifactId>
49+
<scope>test</scope>
50+
</dependency>
4651
</dependencies>
4752

4853
<build>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.hemant.db.exception;
2+
3+
import java.time.Instant;
4+
import java.util.Map;
5+
6+
import com.fasterxml.jackson.annotation.JsonInclude;
7+
8+
@JsonInclude(JsonInclude.Include.NON_NULL)
9+
public class ApiError {
10+
private final Instant timestamp;
11+
private final int status;
12+
private final String error;
13+
private final String message;
14+
private final Map<String, String> details;
15+
16+
public ApiError(int status, String error, String message, Map<String, String> details) {
17+
this.timestamp = Instant.now();
18+
this.status = status;
19+
this.error = error;
20+
this.message = message;
21+
this.details = details;
22+
}
23+
24+
public Instant getTimestamp() {
25+
return timestamp;
26+
}
27+
28+
public int getStatus() {
29+
return status;
30+
}
31+
32+
public String getError() {
33+
return error;
34+
}
35+
36+
public String getMessage() {
37+
return message;
38+
}
39+
40+
public Map<String, String> getDetails() {
41+
return details;
42+
}
43+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.hemant.db.exception;
2+
3+
public class BadRequestException extends RuntimeException {
4+
public BadRequestException(String message) {
5+
super(message);
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.hemant.db.exception;
2+
3+
public class DuplicateResourceException extends RuntimeException {
4+
public DuplicateResourceException(String message) {
5+
super(message);
6+
}
7+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.hemant.db.exception;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
import java.util.stream.Collectors;
6+
7+
import javax.validation.ConstraintViolationException;
8+
9+
import org.springframework.http.HttpStatus;
10+
import org.springframework.http.ResponseEntity;
11+
import org.springframework.validation.FieldError;
12+
import org.springframework.web.bind.MethodArgumentNotValidException;
13+
import org.springframework.web.bind.MissingServletRequestParameterException;
14+
import org.springframework.web.bind.annotation.ExceptionHandler;
15+
import org.springframework.web.bind.annotation.RestControllerAdvice;
16+
17+
@RestControllerAdvice
18+
public class GlobalExceptionHandler {
19+
@ExceptionHandler(ResourceNotFoundException.class)
20+
public ResponseEntity<ApiError> handleResourceNotFound(ResourceNotFoundException ex) {
21+
return buildResponse(HttpStatus.NOT_FOUND, ex.getMessage(), null);
22+
}
23+
24+
@ExceptionHandler(DuplicateResourceException.class)
25+
public ResponseEntity<ApiError> handleDuplicateResource(DuplicateResourceException ex) {
26+
return buildResponse(HttpStatus.CONFLICT, ex.getMessage(), null);
27+
}
28+
29+
@ExceptionHandler(BadRequestException.class)
30+
public ResponseEntity<ApiError> handleBadRequest(BadRequestException ex) {
31+
return buildResponse(HttpStatus.BAD_REQUEST, ex.getMessage(), null);
32+
}
33+
34+
@ExceptionHandler(MethodArgumentNotValidException.class)
35+
public ResponseEntity<ApiError> handleValidationExceptions(MethodArgumentNotValidException ex) {
36+
Map<String, String> details = new HashMap<>();
37+
ex.getBindingResult().getAllErrors().forEach(error -> {
38+
String fieldName = ((FieldError) error).getField();
39+
String errorMessage = error.getDefaultMessage();
40+
details.put(fieldName, errorMessage);
41+
});
42+
return buildResponse(HttpStatus.BAD_REQUEST, "Validation failed", details);
43+
}
44+
45+
@ExceptionHandler(ConstraintViolationException.class)
46+
public ResponseEntity<ApiError> handleConstraintViolation(ConstraintViolationException ex) {
47+
Map<String, String> details = ex.getConstraintViolations().stream()
48+
.collect(Collectors.toMap(
49+
violation -> violation.getPropertyPath().toString(),
50+
violation -> violation.getMessage(),
51+
(left, right) -> left));
52+
return buildResponse(HttpStatus.BAD_REQUEST, "Validation failed", details);
53+
}
54+
55+
@ExceptionHandler(MissingServletRequestParameterException.class)
56+
public ResponseEntity<ApiError> handleMissingParameter(MissingServletRequestParameterException ex) {
57+
return buildResponse(HttpStatus.BAD_REQUEST, ex.getParameterName() + " parameter is required", null);
58+
}
59+
60+
private ResponseEntity<ApiError> buildResponse(HttpStatus status, String message, Map<String, String> details) {
61+
ApiError error = new ApiError(status.value(), status.getReasonPhrase(), message, details);
62+
return new ResponseEntity<>(error, status);
63+
}
64+
}

0 commit comments

Comments
 (0)