diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e6610b3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,25 @@ +name: Java CI + +on: + pull_request: + push: + branches: + - main + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Java 11 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: "11" + cache: maven + + - name: Run tests + run: ./mvnw test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7cdf270 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +target/ +*.class + +.idea/ +.vscode/ +*.iml + +.classpath +.project +.settings/ + +*.log +.env diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..642d572 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/README.md b/README.md index fd5f95f..814a20a 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,178 @@ -# My-SpringBoot-MySQL-Application +# My Spring Boot MySQL Application -# Read Me First -The following was discovered as part of building this project: +This is an educational Spring Boot REST API for managing employees, +departments, addresses, profiles, and simple login/logout state. The app uses +Spring Web, Spring Data JPA, Bean Validation, and MySQL for local development. -* The original package name 'com.hemant.db.springboot-mysql' is invalid and this project uses 'com.hemant.db.springbootmysql' instead. +## Tech Stack -# Getting Started +- Java 11 +- Spring Boot 2.7.x +- Spring Web +- Spring Data JPA +- MySQL Connector/J +- H2 for automated tests +- Maven Wrapper -### Reference Documentation -For further reference, please consider the following sections: +## Project Structure -* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) -* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.5.2/maven-plugin/reference/html/) -* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.5.2/maven-plugin/reference/html/#build-image) -* [Spring Web](https://docs.spring.io/spring-boot/docs/2.5.2/reference/htmlsingle/#boot-features-developing-web-applications) -* [Spring Data JPA](https://docs.spring.io/spring-boot/docs/2.5.2/reference/htmlsingle/#boot-features-jpa-and-spring-data) -* [JDBC API](https://docs.spring.io/spring-boot/docs/2.5.2/reference/htmlsingle/#boot-features-sql) +```text +. +|-- pom.xml +|-- mvnw / mvnw.cmd +|-- src/ +| |-- main/ +| | |-- java/com/hemant/db/ +| | | |-- SpringbootMysqlApplication.java +| | | |-- exception/ +| | | |-- model/ +| | | |-- repository/ +| | | |-- resource/ +| | | `-- service/ +| | `-- resources/application.yml +| `-- test/ +| |-- java/com/hemant/db/ +| `-- resources/application-test.yml +`-- .github/workflows/ci.yml +``` -### Guides -The following guides illustrate how to use some features concretely: +### Main Packages -* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) -* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) -* [Building REST services with Spring](https://spring.io/guides/tutorials/bookmarks/) -* [Accessing Data with JPA](https://spring.io/guides/gs/accessing-data-jpa/) -* [Accessing Relational Data using JDBC with Spring](https://spring.io/guides/gs/relational-data-access/) -* [Managing Transactions](https://spring.io/guides/gs/managing-transactions/) +`model` contains the JPA entities that map to database tables. Examples: +`Employee`, `Department`, `Address`, and `Profile`. + +`repository` contains Spring Data JPA repositories. These interfaces provide +database access methods such as `findByEmail`, `findByCity`, and `findByName`. + +`service` contains business logic. Controllers call services instead of talking +directly to repositories, which keeps request handling and application rules +separate. + +`resource` contains REST controllers. These preserve the original `/rest/...` +routes while delegating work to services. + +`exception` contains shared API error handling. Missing records, duplicate +records, bad requests, and validation failures return consistent JSON error +responses. + +## Configuration + +The app reads database settings from environment variables with local defaults: + +| Variable | Default | +| --- | --- | +| `MYSQL_URL` | `jdbc:mysql://localhost:3306/employee_db` | +| `MYSQL_USERNAME` | `root` | +| `MYSQL_PASSWORD` | empty | +| `JPA_DDL_AUTO` | `update` | +| `JPA_SHOW_SQL` | `true` | + +Example PowerShell setup: + +```powershell +$env:MYSQL_URL="jdbc:mysql://localhost:3306/employee_db" +$env:MYSQL_USERNAME="root" +$env:MYSQL_PASSWORD="your-password" +``` + +## Run Locally + +Start MySQL and create the database: + +```sql +CREATE DATABASE employee_db; +``` + +Then run the application: + +```powershell +.\mvnw.cmd spring-boot:run +``` + +On macOS/Linux: + +```bash +./mvnw spring-boot:run +``` + +The API starts on the default Spring Boot port: + +```text +http://localhost:8080 +``` + +## API Overview + +The existing route style is preserved. + +### Employees + +- `GET /rest/Employee/all` +- `POST /rest/Employee/insert` +- `GET /rest/Employee/findbyname?name=...` +- `GET /rest/Employee/findbydesignation?designation=...` +- `POST /rest/Employee/updatedesignation?Id=...&designation=...` +- `POST /rest/Employee/updatemobile?Id=...&mobile=...` +- `POST /rest/Employee/updatepassword?Id=...&password=...` +- `DELETE /rest/Employee/delete?Id=...` + +### Departments + +- `GET /rest/Department/all` +- `POST /rest/Department/insert` +- `GET /rest/Department/findbyname?name=...` +- `GET /rest/Department/findbyaddress?address=...` +- `POST /rest/Department/updatefloor?Id=...&floor=...` +- `POST /rest/Department/updateaddress?Id=...&address=...` +- `DELETE /rest/Department/delete?Id=...` + +### Addresses + +- `GET /rest/Address/all` +- `POST /rest/Address/insert` +- `GET /rest/Address/findbycity?city=...` +- `GET /rest/Address/findbystate?state=...` +- `POST /rest/Address/updateaddress?...` +- `DELETE /rest/Address/delete?Id=...` + +### Profiles + +- `GET /rest/Profile/all` +- `POST /rest/Profile/insert` +- `GET /rest/Profile/findbygender?gender=...` +- `GET /rest/Profile/findbyhobbies?hobbies=...` +- `POST /rest/Profile/updatehobbies?Id=...&hobbies=...` +- `DELETE /rest/Profile/delete?Id=...` + +### Login + +- `GET /rest/Login/findbyemail?email=...` +- `POST /rest/Login/login?email=...&password=...` +- `POST /rest/Login/logout?email=...` + +## Testing + +Tests use H2 in MySQL compatibility mode, so they do not require a local MySQL +server. + +```powershell +.\mvnw.cmd test +``` + +On macOS/Linux: + +```bash +./mvnw test +``` + +The GitHub Actions workflow also runs the Maven test suite on Java 11 for pushes +to `main` and pull requests. + +## Notes + +- Passwords are accepted for create/update/login operations but are hidden from + JSON responses. +- This project intentionally keeps the original route naming style to avoid + breaking existing clients. +- Authentication is educational only. It stores a login status and plain + password values, so it should not be used as-is for production security. diff --git a/mvnw b/mvnw old mode 100644 new mode 100755 diff --git a/pom.xml b/pom.xml index 7e0c5a2..2a36394 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.5.2 + 2.7.18 com.hemant.db @@ -35,14 +35,19 @@ test - mysql - mysql-connector-java - 8.0.25 + com.mysql + mysql-connector-j + runtime org.springframework.boot spring-boot-starter-validation + + com.h2database + h2 + test + diff --git a/src/main/java/com/hemant/db/exception/ApiError.java b/src/main/java/com/hemant/db/exception/ApiError.java new file mode 100644 index 0000000..eb822d9 --- /dev/null +++ b/src/main/java/com/hemant/db/exception/ApiError.java @@ -0,0 +1,43 @@ +package com.hemant.db.exception; + +import java.time.Instant; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ApiError { + private final Instant timestamp; + private final int status; + private final String error; + private final String message; + private final Map details; + + public ApiError(int status, String error, String message, Map details) { + this.timestamp = Instant.now(); + this.status = status; + this.error = error; + this.message = message; + this.details = details; + } + + public Instant getTimestamp() { + return timestamp; + } + + public int getStatus() { + return status; + } + + public String getError() { + return error; + } + + public String getMessage() { + return message; + } + + public Map getDetails() { + return details; + } +} diff --git a/src/main/java/com/hemant/db/exception/BadRequestException.java b/src/main/java/com/hemant/db/exception/BadRequestException.java new file mode 100644 index 0000000..f4926f0 --- /dev/null +++ b/src/main/java/com/hemant/db/exception/BadRequestException.java @@ -0,0 +1,7 @@ +package com.hemant.db.exception; + +public class BadRequestException extends RuntimeException { + public BadRequestException(String message) { + super(message); + } +} diff --git a/src/main/java/com/hemant/db/exception/DuplicateResourceException.java b/src/main/java/com/hemant/db/exception/DuplicateResourceException.java new file mode 100644 index 0000000..71233d0 --- /dev/null +++ b/src/main/java/com/hemant/db/exception/DuplicateResourceException.java @@ -0,0 +1,7 @@ +package com.hemant.db.exception; + +public class DuplicateResourceException extends RuntimeException { + public DuplicateResourceException(String message) { + super(message); + } +} diff --git a/src/main/java/com/hemant/db/exception/GlobalExceptionHandler.java b/src/main/java/com/hemant/db/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..89334d3 --- /dev/null +++ b/src/main/java/com/hemant/db/exception/GlobalExceptionHandler.java @@ -0,0 +1,64 @@ +package com.hemant.db.exception; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.validation.ConstraintViolationException; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExceptionHandler { + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity handleResourceNotFound(ResourceNotFoundException ex) { + return buildResponse(HttpStatus.NOT_FOUND, ex.getMessage(), null); + } + + @ExceptionHandler(DuplicateResourceException.class) + public ResponseEntity handleDuplicateResource(DuplicateResourceException ex) { + return buildResponse(HttpStatus.CONFLICT, ex.getMessage(), null); + } + + @ExceptionHandler(BadRequestException.class) + public ResponseEntity handleBadRequest(BadRequestException ex) { + return buildResponse(HttpStatus.BAD_REQUEST, ex.getMessage(), null); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity handleValidationExceptions(MethodArgumentNotValidException ex) { + Map details = new HashMap<>(); + ex.getBindingResult().getAllErrors().forEach(error -> { + String fieldName = ((FieldError) error).getField(); + String errorMessage = error.getDefaultMessage(); + details.put(fieldName, errorMessage); + }); + return buildResponse(HttpStatus.BAD_REQUEST, "Validation failed", details); + } + + @ExceptionHandler(ConstraintViolationException.class) + public ResponseEntity handleConstraintViolation(ConstraintViolationException ex) { + Map details = ex.getConstraintViolations().stream() + .collect(Collectors.toMap( + violation -> violation.getPropertyPath().toString(), + violation -> violation.getMessage(), + (left, right) -> left)); + return buildResponse(HttpStatus.BAD_REQUEST, "Validation failed", details); + } + + @ExceptionHandler(MissingServletRequestParameterException.class) + public ResponseEntity handleMissingParameter(MissingServletRequestParameterException ex) { + return buildResponse(HttpStatus.BAD_REQUEST, ex.getParameterName() + " parameter is required", null); + } + + private ResponseEntity buildResponse(HttpStatus status, String message, Map details) { + ApiError error = new ApiError(status.value(), status.getReasonPhrase(), message, details); + return new ResponseEntity<>(error, status); + } +} diff --git a/src/main/java/com/hemant/db/exception/ResourceNotFoundException.java b/src/main/java/com/hemant/db/exception/ResourceNotFoundException.java new file mode 100644 index 0000000..93c7708 --- /dev/null +++ b/src/main/java/com/hemant/db/exception/ResourceNotFoundException.java @@ -0,0 +1,11 @@ +package com.hemant.db.exception; + +public class ResourceNotFoundException extends RuntimeException { + public ResourceNotFoundException(String resourceName, Integer id) { + super(resourceName + " not found with id " + id); + } + + public ResourceNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/hemant/db/model/Address.java b/src/main/java/com/hemant/db/model/Address.java index fc1fe7a..adf24a5 100644 --- a/src/main/java/com/hemant/db/model/Address.java +++ b/src/main/java/com/hemant/db/model/Address.java @@ -5,7 +5,6 @@ import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.validation.constraints.*; -import com.hemant.db.validators.IsInteger; @Entity public class Address { @@ -27,11 +26,9 @@ public class Address { private String state; @Min(value = 100000) @Max(value = 999999) - @IsInteger @NotNull @Column(name = "PIN") private Integer pin; - @IsInteger @Column(name = "Emp_ID") private Integer empId; @NotBlank diff --git a/src/main/java/com/hemant/db/model/Department.java b/src/main/java/com/hemant/db/model/Department.java index b2ea448..30738d8 100644 --- a/src/main/java/com/hemant/db/model/Department.java +++ b/src/main/java/com/hemant/db/model/Department.java @@ -5,7 +5,6 @@ import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.validation.constraints.*; -import com.hemant.db.validators.IsInteger; @Entity public class Department { @@ -20,7 +19,6 @@ public class Department { @Column(name = "Address") private String address; @NotNull - @IsInteger @Max(value = 200) @Column(name = "Floor") private Integer floor; @@ -54,19 +52,19 @@ public void setName(String name) { this.name = name; } - public String getaddress() { + public String getAddress() { return address; } - public void setaddress(String address) { + public void setAddress(String address) { this.address = address; } - public Integer getfloor() { + public Integer getFloor() { return floor; } - public void setfloor(Integer floor) { + public void setFloor(Integer floor) { this.floor = floor; } diff --git a/src/main/java/com/hemant/db/model/Employee.java b/src/main/java/com/hemant/db/model/Employee.java index e2d7e05..e1aeb9e 100644 --- a/src/main/java/com/hemant/db/model/Employee.java +++ b/src/main/java/com/hemant/db/model/Employee.java @@ -5,8 +5,8 @@ import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.validation.constraints.*; -import com.hemant.db.validators.IsInteger; -import com.hemant.db.validators.IsLong; + +import com.fasterxml.jackson.annotation.JsonProperty; @Entity public class Employee { @@ -25,11 +25,9 @@ public class Employee { @Column(name = "Salary") private Integer salary; @NotNull - @IsInteger @Column(name = "Dep_ID") private Integer depId; @NotNull - @IsLong @Min(value = (long)7e9) @Max(value = (long)1e10 - 1) @Column(name = "Mobile") @@ -39,6 +37,7 @@ public class Employee { @Column(name = "EMail") private String email; @NotNull + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) @Column(name = "Password") private String password; @Column(name = "Status") diff --git a/src/main/java/com/hemant/db/model/Profile.java b/src/main/java/com/hemant/db/model/Profile.java index e97202a..df17483 100644 --- a/src/main/java/com/hemant/db/model/Profile.java +++ b/src/main/java/com/hemant/db/model/Profile.java @@ -5,7 +5,6 @@ import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.validation.constraints.*; -import com.hemant.db.validators.IsInteger; @Entity public class Profile { @@ -23,7 +22,6 @@ public class Profile { @NotBlank @Column(name = "Hobbies") private String hobbies; - @IsInteger @NotNull @Column(name = "Emp_ID") private Integer empId; @@ -77,6 +75,10 @@ public Integer getEmpId() { return empId; } + public void setEmpId(Integer empId) { + this.empId = empId; + } + public void setDepId(Integer empId) { this.empId = empId; } diff --git a/src/main/java/com/hemant/db/model/Response.java b/src/main/java/com/hemant/db/model/Response.java index 181ff49..1375d1a 100644 --- a/src/main/java/com/hemant/db/model/Response.java +++ b/src/main/java/com/hemant/db/model/Response.java @@ -2,6 +2,9 @@ import java.io.Serializable; +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_NULL) public class Response implements Serializable { private static final long serialVersionUID = 1L; public boolean status; diff --git a/src/main/java/com/hemant/db/repository/AddressRepository.java b/src/main/java/com/hemant/db/repository/AddressRepository.java index 7f5b7a1..eca3c45 100644 --- a/src/main/java/com/hemant/db/repository/AddressRepository.java +++ b/src/main/java/com/hemant/db/repository/AddressRepository.java @@ -4,24 +4,13 @@ import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; public interface AddressRepository extends JpaRepository { - public List
findByCity(@Param("city") String city); + List
findByCity(String city); - public List
findByState(@Param("state") String state); + List
findByState(String state); - public Optional
findById(@Param("Id") Integer Id); + Optional
findById(Integer id); - @Query("select a from Address a where a.empId = :empId") - public List
findByEmp(@Param("empId") Integer empId); - - @Modifying - @Query("update Address a set a.address1 = :address1, a.address2 = :address2, a.city = :city, a.state = :state, a.pin = :pin where a.Id = :Id") - public List
updateAddress(@Param("Id") Integer Id, @Param("address1") String address1, @Param("address2") String address2, @Param("city") String city, @Param("state") String state, @Param("pin") Integer pin); - - @Modifying - public void deleteById(@Param("Id") Integer Id); + List
findByEmpId(Integer empId); } diff --git a/src/main/java/com/hemant/db/repository/DepartmentRepository.java b/src/main/java/com/hemant/db/repository/DepartmentRepository.java index 899a1a4..bfde5f0 100644 --- a/src/main/java/com/hemant/db/repository/DepartmentRepository.java +++ b/src/main/java/com/hemant/db/repository/DepartmentRepository.java @@ -4,25 +4,11 @@ import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; public interface DepartmentRepository extends JpaRepository { - public List findByName(@Param("name") String Name); + List findByName(String name); - public List findByAddress(@Param("address") String Address); + List findByAddress(String address); - public Optional findById(@Param("Id") Integer Id); - - @Modifying - @Query("update Department d set d.floor = :floor where d.Id = :Id") - public List updateFloor(@Param("Id") Integer Id, @Param("floor") Integer floor); - - @Modifying - @Query("update Department d set d.address = :address where d.Id = :Id") - public List updateAddress(@Param("Id") Integer Id, @Param("address") String address); - - @Modifying - public void deleteById(@Param("Id") Integer Id); + Optional findById(Integer id); } diff --git a/src/main/java/com/hemant/db/repository/EmployeeRepository.java b/src/main/java/com/hemant/db/repository/EmployeeRepository.java index 851d26b..ac8938d 100644 --- a/src/main/java/com/hemant/db/repository/EmployeeRepository.java +++ b/src/main/java/com/hemant/db/repository/EmployeeRepository.java @@ -4,34 +4,15 @@ import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; public interface EmployeeRepository extends JpaRepository { - @Query("select e from Employee e where e.accountStatus = 'Activated'") - public List findAll(); + List findByAccountStatus(String accountStatus); - public List findByName(@Param("name") String Name); + List findByName(String name); - public List findByDesignation(@Param("designation") String Designation); + List findByDesignation(String designation); - public Optional findById(@Param("Id") Integer Id); - - @Modifying - @Query("update Employee e set e.designation = :designation where e.Id = :Id") - public List updateDesignation(@Param("Id") Integer Id, @Param("designation") String designation); - - @Modifying - @Query("update Employee e set e.mobile = :mobile where e.Id = :Id") - public List updateMobile(@Param("Id") Integer Id, @Param("mobile") long mobile); - - @Modifying - @Query("update Employee e set e.password = :password where e.Id = :Id") - public List updatePassword(@Param("Id") Integer Id, @Param("password") String password); - - public Employee findByEmail(@Param("email") String email); - - @Modifying - public void deleteById(@Param("Id") Integer Id); + Optional findById(Integer id); + + Optional findByEmail(String email); } diff --git a/src/main/java/com/hemant/db/repository/ProfileRepository.java b/src/main/java/com/hemant/db/repository/ProfileRepository.java index e8e8a75..8a2e429 100644 --- a/src/main/java/com/hemant/db/repository/ProfileRepository.java +++ b/src/main/java/com/hemant/db/repository/ProfileRepository.java @@ -4,21 +4,11 @@ import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; public interface ProfileRepository extends JpaRepository { - public List findByGender(@Param("gender") String Gender); + List findByGender(String gender); - public List findByHobbies(@Param("hobbies") String Hobbies); + List findByHobbies(String hobbies); - public Optional findById(@Param("Id") Integer Id); - - @Modifying - @Query("update Profile p set p.hobbies = :hobbies where p.Id = :Id") - public List updateHobbies(@Param("Id") Integer Id, @Param("hobbies") String hobbies); - - @Modifying - public void deleteById(@Param("Id") Integer Id); + Optional findById(Integer id); } diff --git a/src/main/java/com/hemant/db/resource/AddressResource.java b/src/main/java/com/hemant/db/resource/AddressResource.java index e0fbfd4..db29fc2 100644 --- a/src/main/java/com/hemant/db/resource/AddressResource.java +++ b/src/main/java/com/hemant/db/resource/AddressResource.java @@ -1,73 +1,67 @@ package com.hemant.db.resource; -import com.hemant.db.model.Address; -import com.hemant.db.repository.AddressRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.*; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.FieldError; -import java.util.HashMap; import java.util.List; -import java.util.Map; + import javax.validation.Valid; +import javax.validation.constraints.NotBlank; + +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.hemant.db.model.Address; +import com.hemant.db.service.AddressService; +@Validated @RestController @RequestMapping(value = "/rest/Address") public class AddressResource { - - @Autowired - AddressRepository AddressRepository; + private final AddressService addressService; + + public AddressResource(AddressService addressService) { + this.addressService = addressService; + } @GetMapping(value = "/all") public List
getAll() { - return AddressRepository.findAll(); + return addressService.getAllAddresses(); } @PostMapping(value = "/insert") - public ResponseEntity> persist(@Valid @RequestBody final Address Address) { - AddressRepository.save(Address); - return ResponseEntity.ok(AddressRepository.findByEmp(Address.getEmpId())); - } - + public ResponseEntity> persist(@Valid @RequestBody final Address address) { + return ResponseEntity.ok(addressService.createAddress(address)); + } + @GetMapping(value = "/findbycity") - public List
fetchDataByCity(@Valid @RequestParam("city") String city) { - return AddressRepository.findByCity(city); + public List
fetchDataByCity(@RequestParam("city") @NotBlank String city) { + return addressService.findByCity(city); } - + @GetMapping(value = "/findbystate") - public List
fetchDataByState(@Valid @RequestParam("state") String state) { - return AddressRepository.findByState(state); + public List
fetchDataByState(@RequestParam("state") @NotBlank String state) { + return addressService.findByState(state); } - + @PostMapping("/updateaddress") - public ResponseEntity
updateAddress(@RequestParam("Id") Integer Id, @Valid @RequestParam("address1") String address1, @Valid @RequestParam("address2") String address2, @Valid @RequestParam("city") String city, @Valid @RequestParam("state") String state, @Valid @RequestParam("pin") Integer pin) { - Address a = AddressRepository.findById(Id).get(); - a.setAddress1(address1); a.setAddress2(address2); a.setCity(city); a.setState(state); a.setPIN(pin); - AddressRepository.save(a); - return ResponseEntity.ok(a); + public ResponseEntity
updateAddress( + @RequestParam("Id") Integer id, + @RequestParam("address1") @NotBlank String address1, + @RequestParam("address2") @NotBlank String address2, + @RequestParam("city") @NotBlank String city, + @RequestParam("state") @NotBlank String state, + @RequestParam("pin") Integer pin) { + return ResponseEntity.ok(addressService.updateAddress(id, address1, address2, city, state, pin)); } - + @DeleteMapping("/delete") - public ResponseEntity deleteUser(@RequestParam("Id") Integer Id){ - try { - AddressRepository.deleteById(Id); - return ResponseEntity.ok("Success"); - } catch(Exception e) { - return new ResponseEntity<>("Error: " + e.getMessage(), HttpStatus.BAD_REQUEST); - } - } - - @ResponseStatus(HttpStatus.BAD_REQUEST) - @ExceptionHandler(MethodArgumentNotValidException.class) - public Map handleValidationExceptions(MethodArgumentNotValidException ex) { - Map errors = new HashMap<>(); - ex.getBindingResult().getAllErrors().forEach((error) -> { - String fieldName = ((FieldError) error).getField(); - String errorMessage = error.getDefaultMessage(); - errors.put(fieldName, errorMessage); - }); - return errors; + public ResponseEntity deleteUser(@RequestParam("Id") Integer id) { + addressService.deleteAddress(id); + return ResponseEntity.ok("Success"); } } diff --git a/src/main/java/com/hemant/db/resource/DepartmentResource.java b/src/main/java/com/hemant/db/resource/DepartmentResource.java index 45c8151..32e6066 100644 --- a/src/main/java/com/hemant/db/resource/DepartmentResource.java +++ b/src/main/java/com/hemant/db/resource/DepartmentResource.java @@ -1,81 +1,70 @@ package com.hemant.db.resource; -import com.hemant.db.model.Department; -import com.hemant.db.repository.DepartmentRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.*; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.FieldError; -import java.util.HashMap; import java.util.List; -import java.util.Map; + import javax.validation.Valid; +import javax.validation.constraints.NotBlank; + +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.hemant.db.model.Department; +import com.hemant.db.service.DepartmentService; +@Validated @RestController @RequestMapping(value = "/rest/Department") public class DepartmentResource { + private final DepartmentService departmentService; - @Autowired - DepartmentRepository DepartmentRepository; + public DepartmentResource(DepartmentService departmentService) { + this.departmentService = departmentService; + } @GetMapping(value = "/all") public List getAll() { - return DepartmentRepository.findAll(); + return departmentService.getAllDepartments(); } @PostMapping(value = "/insert") - public ResponseEntity<@Valid Department> persist(@Valid @RequestBody final Department Department) { - DepartmentRepository.save(Department); - return ResponseEntity.ok(Department); + public ResponseEntity persist(@Valid @RequestBody final Department department) { + return ResponseEntity.ok(departmentService.createDepartment(department)); } - + @GetMapping("/findbyname") - public List fetchDataByName(@Valid @RequestParam("name") String name){ - return DepartmentRepository.findByName(name); + public List fetchDataByName(@RequestParam("name") @NotBlank String name) { + return departmentService.findByName(name); } - + @GetMapping("/findbyaddress") - public List fetchDataByAddress(@Valid @RequestParam("address") String address){ - return DepartmentRepository.findByAddress(address); + public List fetchDataByAddress(@RequestParam("address") @NotBlank String address) { + return departmentService.findByAddress(address); } - + @PostMapping("/updatefloor") - public ResponseEntity updateFloor(@RequestParam("Id") Integer Id, @Valid @RequestParam("floor") Integer floor) { - Department d = DepartmentRepository.findById(Id).get(); - d.setfloor(floor); - DepartmentRepository.save(d); - return ResponseEntity.ok(d); + public ResponseEntity updateFloor( + @RequestParam("Id") Integer id, + @RequestParam("floor") Integer floor) { + return ResponseEntity.ok(departmentService.updateFloor(id, floor)); } - + @PostMapping("/updateaddress") - public ResponseEntity updateAddress(@RequestParam("Id") Integer Id, @Valid @RequestParam("address") String address) { - Department d = DepartmentRepository.findById(Id).get(); - d.setaddress(address); - DepartmentRepository.save(d); - return ResponseEntity.ok(d); + public ResponseEntity updateAddress( + @RequestParam("Id") Integer id, + @RequestParam("address") @NotBlank String address) { + return ResponseEntity.ok(departmentService.updateAddress(id, address)); } - + @DeleteMapping("/delete") - public ResponseEntity deleteDepartment(@RequestParam("Id") Integer Id){ - try { - DepartmentRepository.deleteById(Id); - return ResponseEntity.ok("Success"); - } catch(Exception e) { - return new ResponseEntity<>("Error: " + e.getMessage(), HttpStatus.BAD_REQUEST); - } - } - - @ResponseStatus(HttpStatus.BAD_REQUEST) - @ExceptionHandler(MethodArgumentNotValidException.class) - public Map handleValidationExceptions(MethodArgumentNotValidException ex) { - Map errors = new HashMap<>(); - ex.getBindingResult().getAllErrors().forEach((error) -> { - String fieldName = ((FieldError) error).getField(); - String errorMessage = error.getDefaultMessage(); - errors.put(fieldName, errorMessage); - }); - return errors; + public ResponseEntity deleteDepartment(@RequestParam("Id") Integer id) { + departmentService.deleteDepartment(id); + return ResponseEntity.ok("Success"); } } diff --git a/src/main/java/com/hemant/db/resource/EmployeeResource.java b/src/main/java/com/hemant/db/resource/EmployeeResource.java index 0dd400b..1479143 100644 --- a/src/main/java/com/hemant/db/resource/EmployeeResource.java +++ b/src/main/java/com/hemant/db/resource/EmployeeResource.java @@ -1,101 +1,76 @@ package com.hemant.db.resource; -import com.hemant.db.model.Employee; -import com.hemant.db.repository.EmployeeRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.*; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.FieldError; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Optional; + import javax.validation.Valid; +import javax.validation.constraints.NotBlank; + +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.hemant.db.model.Employee; +import com.hemant.db.service.EmployeeService; +@Validated @RestController @RequestMapping(value = "/rest/Employee") public class EmployeeResource { + private final EmployeeService employeeService; - @Autowired - EmployeeRepository EmployeeRepository; + public EmployeeResource(EmployeeService employeeService) { + this.employeeService = employeeService; + } @GetMapping(value = "/all") public List getAll() { - return EmployeeRepository.findAll(); + return employeeService.getAllEmployees(); } @PostMapping(value = "/insert") - public ResponseEntity<@Valid Employee> persist(@Valid @RequestBody final Employee Employee) { - try { - EmployeeRepository.save(Employee); - return ResponseEntity.ok(Employee); - } catch(Exception e) { - Employee E = EmployeeRepository.findByEmail(Employee.getEmail()); - E.setAccountStatus("Activated"); - EmployeeRepository.save(E); - return ResponseEntity.ok(E); - } - } - + public ResponseEntity persist(@Valid @RequestBody final Employee employee) { + return ResponseEntity.ok(employeeService.createEmployee(employee)); + } + @GetMapping("/findbyname") - public List fetchDataByName(@Valid @RequestParam("name") String name){ - return EmployeeRepository.findByName(name); + public List fetchDataByName(@RequestParam("name") @NotBlank String name) { + return employeeService.findByName(name); } - + @GetMapping("/findbydesignation") - public List fetchDataByDesignation(@Valid @RequestParam("designation") String designation){ - return EmployeeRepository.findByDesignation(designation); + public List fetchDataByDesignation(@RequestParam("designation") @NotBlank String designation) { + return employeeService.findByDesignation(designation); } - + @PostMapping("/updatedesignation") - public ResponseEntity updateDesignation(@RequestParam("Id") Integer Id, @Valid @RequestParam("designation") String designation) { - Employee e = EmployeeRepository.findById(Id).get(); - e.setDesignation(designation); - EmployeeRepository.save(e); - return ResponseEntity.ok(e); + public ResponseEntity updateDesignation( + @RequestParam("Id") Integer id, + @RequestParam("designation") @NotBlank String designation) { + return ResponseEntity.ok(employeeService.updateDesignation(id, designation)); } - + @PostMapping("/updatemobile") - public ResponseEntity updateMobile(@RequestParam("Id") Integer Id, @Valid @RequestParam("mobile") long mobile) { - Employee e = EmployeeRepository.findById(Id).get(); - e.setMobile(mobile); - EmployeeRepository.save(e); - return ResponseEntity.ok(e); + public ResponseEntity updateMobile( + @RequestParam("Id") Integer id, + @RequestParam("mobile") long mobile) { + return ResponseEntity.ok(employeeService.updateMobile(id, mobile)); } - + @PostMapping("/updatepassword") - public ResponseEntity updatePassword(@RequestParam("Id") Integer Id, @Valid @RequestParam("password") String password) { - Employee e = EmployeeRepository.findById(Id).get(); - e.setPassword(password); - EmployeeRepository.save(e); - return ResponseEntity.ok(e); + public ResponseEntity updatePassword( + @RequestParam("Id") Integer id, + @RequestParam("password") @NotBlank String password) { + return ResponseEntity.ok(employeeService.updatePassword(id, password)); } - + @DeleteMapping("/delete") - public ResponseEntity deleteUser(@RequestParam("Id") Integer Id){ - Optional o = EmployeeRepository.findById(Id); - if(o.isPresent()) { - Employee e = o.get(); - e.setAccountStatus("Deactivated"); - EmployeeRepository.save(e); - return ResponseEntity.ok(e); - } - else { - return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST); - } - } - - @ResponseStatus(HttpStatus.BAD_REQUEST) - @ExceptionHandler(MethodArgumentNotValidException.class) - public Map handleValidationExceptions(MethodArgumentNotValidException ex) { - Map errors = new HashMap<>(); - ex.getBindingResult().getAllErrors().forEach((error) -> { - String fieldName = ((FieldError) error).getField(); - String errorMessage = error.getDefaultMessage(); - errors.put(fieldName, errorMessage); - }); - return errors; + public ResponseEntity deleteUser(@RequestParam("Id") Integer id) { + return ResponseEntity.ok(employeeService.deactivateEmployee(id)); } } diff --git a/src/main/java/com/hemant/db/resource/LoginResource.java b/src/main/java/com/hemant/db/resource/LoginResource.java index 7710f89..d61d78d 100644 --- a/src/main/java/com/hemant/db/resource/LoginResource.java +++ b/src/main/java/com/hemant/db/resource/LoginResource.java @@ -1,89 +1,46 @@ package com.hemant.db.resource; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; + +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + import com.hemant.db.model.Employee; -import com.hemant.db.repository.EmployeeRepository; import com.hemant.db.model.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.*; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.FieldError; -import java.util.HashMap; -import java.util.Map; -import javax.validation.Valid; +import com.hemant.db.service.LoginService; +import com.hemant.db.service.LoginService.LoginResult; +@Validated @RestController @RequestMapping(value = "/rest/Login") public class LoginResource { - - @Autowired - EmployeeRepository EmployeeRepository; - - @GetMapping("/findbyemail") - public Employee fetchByEmail(@Valid @RequestParam("email") String email) { - return EmployeeRepository.findByEmail(email); - } - - @PostMapping("/login") - public ResponseEntity login(@Valid @RequestParam("email") String email, @Valid @RequestParam("password") String password) { - Response r = new Response(); - Employee e = EmployeeRepository.findByEmail(email); - try { - String correctPassword = e.getPassword(); - if(e.getStatus().equals("Logged In")) { - r.setStatus(false); - r.setEmployee(e); - return new ResponseEntity<>(r, HttpStatus.FORBIDDEN); - } - else { - if(password.equals(correctPassword)) { - e.setStatus("Logged In"); - EmployeeRepository.save(e); - r.setStatus(true); - r.setEmployee(e); - return new ResponseEntity<>(r, HttpStatus.OK); - } - else { - r.setStatus(false); - r.setMessage("Incorrect Email or Password"); - return new ResponseEntity<>(r, HttpStatus.BAD_REQUEST); - } - } - } catch(Exception e1) { - r.setStatus(false); - r.setMessage("Something went wrong " + e1.getMessage()); - return new ResponseEntity<>(r, HttpStatus.BAD_REQUEST); - } - - } - - @PostMapping("/logout") - public ResponseEntity logout(@Valid @RequestParam("email") String email) { - Employee e = EmployeeRepository.findByEmail(email); - try { - if(e.getStatus().equals("Logged In")) { - e.setStatus("Logged Out"); - EmployeeRepository.save(e); - return new ResponseEntity<>("Logged Out", HttpStatus.OK); - } - else { - return new ResponseEntity<>("Error: User Already logged out", HttpStatus.FORBIDDEN); - } - } catch(Exception e1) { - return new ResponseEntity<>("Error: " + e1.getMessage(), HttpStatus.BAD_REQUEST); - } - } - - @ResponseStatus(HttpStatus.BAD_REQUEST) - @ExceptionHandler(MethodArgumentNotValidException.class) - public Map handleValidationExceptions(MethodArgumentNotValidException ex) { - Map errors = new HashMap<>(); - ex.getBindingResult().getAllErrors().forEach((error) -> { - String fieldName = ((FieldError) error).getField(); - String errorMessage = error.getDefaultMessage(); - errors.put(fieldName, errorMessage); - }); - return errors; + private final LoginService loginService; + + public LoginResource(LoginService loginService) { + this.loginService = loginService; + } + + @GetMapping("/findbyemail") + public Employee fetchByEmail(@RequestParam("email") @Email String email) { + return loginService.findByEmail(email); + } + + @PostMapping("/login") + public ResponseEntity login( + @RequestParam("email") @Email String email, + @RequestParam("password") @NotBlank String password) { + LoginResult result = loginService.login(email, password); + return new ResponseEntity<>(result.getResponse(), result.getStatus()); + } + + @PostMapping("/logout") + public ResponseEntity logout(@RequestParam("email") @Email String email) { + return ResponseEntity.ok(loginService.logout(email)); } } diff --git a/src/main/java/com/hemant/db/resource/ProfileResource.java b/src/main/java/com/hemant/db/resource/ProfileResource.java index 34194ca..2297f36 100644 --- a/src/main/java/com/hemant/db/resource/ProfileResource.java +++ b/src/main/java/com/hemant/db/resource/ProfileResource.java @@ -1,77 +1,63 @@ package com.hemant.db.resource; -import com.hemant.db.model.Profile; -import com.hemant.db.repository.ProfileRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.*; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.FieldError; -import java.util.HashMap; import java.util.List; -import java.util.Map; + import javax.validation.Valid; +import javax.validation.constraints.NotBlank; + +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.hemant.db.model.Profile; +import com.hemant.db.service.ProfileService; +@Validated @RestController @RequestMapping(value = "/rest/Profile") public class ProfileResource { + private final ProfileService profileService; - @Autowired - ProfileRepository ProfileRepository; + public ProfileResource(ProfileService profileService) { + this.profileService = profileService; + } @GetMapping(value = "/all") public List getAll() { - return ProfileRepository.findAll(); + return profileService.getAllProfiles(); } @PostMapping(value = "/insert") - public ResponseEntity<@Valid Profile> persist(@Valid @RequestBody final Profile Profile) { - try { - ProfileRepository.save(Profile); - return ResponseEntity.ok(Profile); - } catch(Exception e) { - return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST); - } + public ResponseEntity persist(@Valid @RequestBody final Profile profile) { + return ResponseEntity.ok(profileService.createProfile(profile)); } - + @GetMapping("/findbygender") - public List fetchDataByGender(@Valid @RequestParam("gender") String gender){ - return ProfileRepository.findByGender(gender); + public List fetchDataByGender(@RequestParam("gender") @NotBlank String gender) { + return profileService.findByGender(gender); } - + @GetMapping("/findbyhobbies") - public List fetchDataByHobbies(@Valid @RequestParam("hobbies") String hobbies){ - return ProfileRepository.findByHobbies(hobbies); + public List fetchDataByHobbies(@RequestParam("hobbies") @NotBlank String hobbies) { + return profileService.findByHobbies(hobbies); } - + @PostMapping("/updatehobbies") - public ResponseEntity updateHobbies(@RequestParam("Id") Integer Id, @Valid @RequestParam("hobbies") String hobbies) { - Profile p = ProfileRepository.findById(Id).get(); - p.setHobbies(hobbies); - ProfileRepository.save(p); - return ResponseEntity.ok(p); + public ResponseEntity updateHobbies( + @RequestParam("Id") Integer id, + @RequestParam("hobbies") @NotBlank String hobbies) { + return ResponseEntity.ok(profileService.updateHobbies(id, hobbies)); } - + @DeleteMapping("/delete") - public ResponseEntity deleteProfile(@RequestParam("Id") Integer Id){ - try { - ProfileRepository.deleteById(Id); - return ResponseEntity.ok("Success"); - } catch(Exception e) { - return new ResponseEntity<>("Error: " + e.getMessage(), HttpStatus.BAD_REQUEST); - } - } - - @ResponseStatus(HttpStatus.BAD_REQUEST) - @ExceptionHandler(MethodArgumentNotValidException.class) - public Map handleValidationExceptions(MethodArgumentNotValidException ex) { - Map errors = new HashMap<>(); - ex.getBindingResult().getAllErrors().forEach((error) -> { - String fieldName = ((FieldError) error).getField(); - String errorMessage = error.getDefaultMessage(); - errors.put(fieldName, errorMessage); - }); - return errors; + public ResponseEntity deleteProfile(@RequestParam("Id") Integer id) { + profileService.deleteProfile(id); + return ResponseEntity.ok("Success"); } } diff --git a/src/main/java/com/hemant/db/service/AddressService.java b/src/main/java/com/hemant/db/service/AddressService.java new file mode 100644 index 0000000..bba960f --- /dev/null +++ b/src/main/java/com/hemant/db/service/AddressService.java @@ -0,0 +1,58 @@ +package com.hemant.db.service; + +import java.util.List; + +import javax.transaction.Transactional; + +import org.springframework.stereotype.Service; + +import com.hemant.db.exception.ResourceNotFoundException; +import com.hemant.db.model.Address; +import com.hemant.db.repository.AddressRepository; + +@Service +@Transactional +public class AddressService { + private final AddressRepository addressRepository; + + public AddressService(AddressRepository addressRepository) { + this.addressRepository = addressRepository; + } + + public List
getAllAddresses() { + return addressRepository.findAll(); + } + + public List
createAddress(Address address) { + addressRepository.save(address); + return addressRepository.findByEmpId(address.getEmpId()); + } + + public List
findByCity(String city) { + return addressRepository.findByCity(city); + } + + public List
findByState(String state) { + return addressRepository.findByState(state); + } + + public Address updateAddress(Integer id, String address1, String address2, String city, String state, Integer pin) { + Address address = findById(id); + address.setAddress1(address1); + address.setAddress2(address2); + address.setCity(city); + address.setState(state); + address.setPIN(pin); + return addressRepository.save(address); + } + + public void deleteAddress(Integer id) { + Address address = findById(id); + addressRepository.delete(address); + } + + private Address findById(Integer id) { + return addressRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("Address", id)); + } +} diff --git a/src/main/java/com/hemant/db/service/DepartmentService.java b/src/main/java/com/hemant/db/service/DepartmentService.java new file mode 100644 index 0000000..24b625d --- /dev/null +++ b/src/main/java/com/hemant/db/service/DepartmentService.java @@ -0,0 +1,59 @@ +package com.hemant.db.service; + +import java.util.List; + +import javax.transaction.Transactional; + +import org.springframework.stereotype.Service; + +import com.hemant.db.exception.ResourceNotFoundException; +import com.hemant.db.model.Department; +import com.hemant.db.repository.DepartmentRepository; + +@Service +@Transactional +public class DepartmentService { + private final DepartmentRepository departmentRepository; + + public DepartmentService(DepartmentRepository departmentRepository) { + this.departmentRepository = departmentRepository; + } + + public List getAllDepartments() { + return departmentRepository.findAll(); + } + + public Department createDepartment(Department department) { + return departmentRepository.save(department); + } + + public List findByName(String name) { + return departmentRepository.findByName(name); + } + + public List findByAddress(String address) { + return departmentRepository.findByAddress(address); + } + + public Department updateFloor(Integer id, Integer floor) { + Department department = findById(id); + department.setFloor(floor); + return departmentRepository.save(department); + } + + public Department updateAddress(Integer id, String address) { + Department department = findById(id); + department.setAddress(address); + return departmentRepository.save(department); + } + + public void deleteDepartment(Integer id) { + Department department = findById(id); + departmentRepository.delete(department); + } + + private Department findById(Integer id) { + return departmentRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("Department", id)); + } +} diff --git a/src/main/java/com/hemant/db/service/EmployeeService.java b/src/main/java/com/hemant/db/service/EmployeeService.java new file mode 100644 index 0000000..d3e8eb2 --- /dev/null +++ b/src/main/java/com/hemant/db/service/EmployeeService.java @@ -0,0 +1,82 @@ +package com.hemant.db.service; + +import java.util.List; + +import javax.transaction.Transactional; + +import org.springframework.stereotype.Service; + +import com.hemant.db.exception.DuplicateResourceException; +import com.hemant.db.exception.ResourceNotFoundException; +import com.hemant.db.model.Employee; +import com.hemant.db.repository.EmployeeRepository; + +@Service +@Transactional +public class EmployeeService { + private final EmployeeRepository employeeRepository; + + public EmployeeService(EmployeeRepository employeeRepository) { + this.employeeRepository = employeeRepository; + } + + public List getAllEmployees() { + return employeeRepository.findByAccountStatus("Activated"); + } + + public Employee createEmployee(Employee employee) { + return employeeRepository.findByEmail(employee.getEmail()) + .map(existingEmployee -> reactivateOrRejectDuplicate(existingEmployee, employee.getEmail())) + .orElseGet(() -> employeeRepository.save(employee)); + } + + public List findByName(String name) { + return employeeRepository.findByName(name); + } + + public List findByDesignation(String designation) { + return employeeRepository.findByDesignation(designation); + } + + public Employee updateDesignation(Integer id, String designation) { + Employee employee = findById(id); + employee.setDesignation(designation); + return employeeRepository.save(employee); + } + + public Employee updateMobile(Integer id, long mobile) { + Employee employee = findById(id); + employee.setMobile(mobile); + return employeeRepository.save(employee); + } + + public Employee updatePassword(Integer id, String password) { + Employee employee = findById(id); + employee.setPassword(password); + return employeeRepository.save(employee); + } + + public Employee deactivateEmployee(Integer id) { + Employee employee = findById(id); + employee.setAccountStatus("Deactivated"); + return employeeRepository.save(employee); + } + + public Employee findByEmail(String email) { + return employeeRepository.findByEmail(email) + .orElseThrow(() -> new ResourceNotFoundException("Employee not found with email " + email)); + } + + public Employee findById(Integer id) { + return employeeRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("Employee", id)); + } + + private Employee reactivateOrRejectDuplicate(Employee existingEmployee, String email) { + if ("Deactivated".equalsIgnoreCase(existingEmployee.getAccountStatus())) { + existingEmployee.setAccountStatus("Activated"); + return employeeRepository.save(existingEmployee); + } + throw new DuplicateResourceException("Employee already exists with email " + email); + } +} diff --git a/src/main/java/com/hemant/db/service/LoginService.java b/src/main/java/com/hemant/db/service/LoginService.java new file mode 100644 index 0000000..9ca363e --- /dev/null +++ b/src/main/java/com/hemant/db/service/LoginService.java @@ -0,0 +1,84 @@ +package com.hemant.db.service; + +import javax.transaction.Transactional; + +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import com.hemant.db.exception.BadRequestException; +import com.hemant.db.exception.ResourceNotFoundException; +import com.hemant.db.model.Employee; +import com.hemant.db.model.Response; +import com.hemant.db.repository.EmployeeRepository; + +@Service +@Transactional +public class LoginService { + private final EmployeeRepository employeeRepository; + + public LoginService(EmployeeRepository employeeRepository) { + this.employeeRepository = employeeRepository; + } + + public Employee findByEmail(String email) { + return employeeRepository.findByEmail(email) + .orElseThrow(() -> new ResourceNotFoundException("Employee not found with email " + email)); + } + + public LoginResult login(String email, String password) { + Employee employee = employeeRepository.findByEmail(email) + .orElseThrow(() -> new BadRequestException("Incorrect Email or Password")); + + Response response = new Response(); + response.setEmployee(employee); + + if ("Logged In".equals(employee.getStatus())) { + response.setStatus(false); + response.setMessage("User is already logged in"); + return new LoginResult(response, HttpStatus.FORBIDDEN); + } + + if (!password.equals(employee.getPassword())) { + response.setStatus(false); + response.setMessage("Incorrect Email or Password"); + response.setEmployee(null); + return new LoginResult(response, HttpStatus.BAD_REQUEST); + } + + employee.setStatus("Logged In"); + employeeRepository.save(employee); + response.setStatus(true); + response.setMessage("Logged In"); + response.setEmployee(employee); + return new LoginResult(response, HttpStatus.OK); + } + + public String logout(String email) { + Employee employee = findByEmail(email); + if (!"Logged In".equals(employee.getStatus())) { + throw new BadRequestException("User is already logged out"); + } + + employee.setStatus("Logged Out"); + employeeRepository.save(employee); + return "Logged Out"; + } + + public static class LoginResult { + private final Response response; + private final HttpStatus status; + + public LoginResult(Response response, HttpStatus status) { + this.response = response; + this.status = status; + } + + public Response getResponse() { + return response; + } + + public HttpStatus getStatus() { + return status; + } + } +} diff --git a/src/main/java/com/hemant/db/service/ProfileService.java b/src/main/java/com/hemant/db/service/ProfileService.java new file mode 100644 index 0000000..32ea476 --- /dev/null +++ b/src/main/java/com/hemant/db/service/ProfileService.java @@ -0,0 +1,53 @@ +package com.hemant.db.service; + +import java.util.List; + +import javax.transaction.Transactional; + +import org.springframework.stereotype.Service; + +import com.hemant.db.exception.ResourceNotFoundException; +import com.hemant.db.model.Profile; +import com.hemant.db.repository.ProfileRepository; + +@Service +@Transactional +public class ProfileService { + private final ProfileRepository profileRepository; + + public ProfileService(ProfileRepository profileRepository) { + this.profileRepository = profileRepository; + } + + public List getAllProfiles() { + return profileRepository.findAll(); + } + + public Profile createProfile(Profile profile) { + return profileRepository.save(profile); + } + + public List findByGender(String gender) { + return profileRepository.findByGender(gender); + } + + public List findByHobbies(String hobbies) { + return profileRepository.findByHobbies(hobbies); + } + + public Profile updateHobbies(Integer id, String hobbies) { + Profile profile = findById(id); + profile.setHobbies(hobbies); + return profileRepository.save(profile); + } + + public void deleteProfile(Integer id) { + Profile profile = findById(id); + profileRepository.delete(profile); + } + + private Profile findById(Integer id) { + return profileRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("Profile", id)); + } +} diff --git a/src/main/java/com/hemant/db/validators/IntegerValidator.java b/src/main/java/com/hemant/db/validators/IntegerValidator.java deleted file mode 100644 index 77b3eae..0000000 --- a/src/main/java/com/hemant/db/validators/IntegerValidator.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.hemant.db.validators; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; - -public class IntegerValidator implements ConstraintValidator{ - public boolean isValid(Integer Id, ConstraintValidatorContext constraintValidatorContext) { - if(Id instanceof Integer) { - return true; - } else { - return false; - } - } -} diff --git a/src/main/java/com/hemant/db/validators/IsInteger.java b/src/main/java/com/hemant/db/validators/IsInteger.java deleted file mode 100644 index 872e47c..0000000 --- a/src/main/java/com/hemant/db/validators/IsInteger.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.hemant.db.validators; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -@Documented -@Constraint(validatedBy = IntegerValidator.class) -@Target({FIELD, PARAMETER}) -@Retention(RUNTIME) -public @interface IsInteger { - String message() default "Should be an Integer"; - Class[] groups() default {}; - Class[] payload() default {}; -} diff --git a/src/main/java/com/hemant/db/validators/IsLong.java b/src/main/java/com/hemant/db/validators/IsLong.java deleted file mode 100644 index 1791824..0000000 --- a/src/main/java/com/hemant/db/validators/IsLong.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.hemant.db.validators; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -@Documented -@Constraint(validatedBy = LongValidator.class) -@Target({FIELD, PARAMETER}) -@Retention(RUNTIME) -public @interface IsLong { - String message() default "Should be a Long Integer"; - Class[] groups() default {}; - Class[] payload() default {}; -} diff --git a/src/main/java/com/hemant/db/validators/LongValidator.java b/src/main/java/com/hemant/db/validators/LongValidator.java deleted file mode 100644 index 84efeb4..0000000 --- a/src/main/java/com/hemant/db/validators/LongValidator.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.hemant.db.validators; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; - -public class LongValidator implements ConstraintValidator { - public boolean isValid(java.lang.Long Id, ConstraintValidatorContext constraintValidatorContext) { - if(Id instanceof java.lang.Long) { - return true; - } else { - return false; - } - } -} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index cfb93a1..7fbb32a 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,10 +1,14 @@ spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver - password: "" #your user - url: jdbc:mysql://localhost:3306/Your_DB - username: "" #your password + url: ${MYSQL_URL:jdbc:mysql://localhost:3306/employee_db} + username: ${MYSQL_USERNAME:root} + password: ${MYSQL_PASSWORD:} jpa: - hibernate.ddl-auto: update + hibernate: + ddl-auto: ${JPA_DDL_AUTO:update} generate-ddl: true - show-sql: true + show-sql: ${JPA_SHOW_SQL:true} + properties: + hibernate: + dialect: org.hibernate.dialect.MySQL8Dialect diff --git a/src/test/java/com/hemant/db/resource/RestApiIntegrationTest.java b/src/test/java/com/hemant/db/resource/RestApiIntegrationTest.java new file mode 100644 index 0000000..caa2e65 --- /dev/null +++ b/src/test/java/com/hemant/db/resource/RestApiIntegrationTest.java @@ -0,0 +1,298 @@ +package com.hemant.db.resource; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.hasSize; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; + +import com.hemant.db.model.Address; +import com.hemant.db.model.Department; +import com.hemant.db.model.Employee; +import com.hemant.db.model.Profile; +import com.hemant.db.repository.AddressRepository; +import com.hemant.db.repository.DepartmentRepository; +import com.hemant.db.repository.EmployeeRepository; +import com.hemant.db.repository.ProfileRepository; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class RestApiIntegrationTest { + @Autowired + private MockMvc mockMvc; + + @Autowired + private EmployeeRepository employeeRepository; + + @Autowired + private DepartmentRepository departmentRepository; + + @Autowired + private AddressRepository addressRepository; + + @Autowired + private ProfileRepository profileRepository; + + @BeforeEach + void cleanDatabase() { + addressRepository.deleteAll(); + profileRepository.deleteAll(); + employeeRepository.deleteAll(); + departmentRepository.deleteAll(); + } + + @Test + void employeeCrudAndValidationErrorsUseSafeResponses() throws Exception { + mockMvc.perform(post("/rest/Employee/insert") + .contentType(MediaType.APPLICATION_JSON) + .content(employeeJson("employee@example.com"))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.email").value("employee@example.com")) + .andExpect(jsonPath("$.password").doesNotExist()); + + Employee employee = employeeRepository.findByEmail("employee@example.com").orElseThrow(); + + mockMvc.perform(get("/rest/Employee/all")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(1))) + .andExpect(jsonPath("$[0].email").value("employee@example.com")) + .andExpect(jsonPath("$[0].password").doesNotExist()); + + mockMvc.perform(get("/rest/Employee/findbyname").param("name", "Test Employee")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].designation").value("Developer")); + + mockMvc.perform(post("/rest/Employee/updatedesignation") + .param("Id", employee.getId().toString()) + .param("designation", "Manager")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.designation").value("Manager")) + .andExpect(jsonPath("$.password").doesNotExist()); + + mockMvc.perform(delete("/rest/Employee/delete").param("Id", employee.getId().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.accountStatus").value("Deactivated")); + + mockMvc.perform(post("/rest/Employee/updatemobile") + .param("Id", "999") + .param("mobile", "9876543210")) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.message", containsString("Employee not found with id 999"))); + + mockMvc.perform(post("/rest/Employee/insert") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"Invalid\"}")) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.message").value("Validation failed")) + .andExpect(jsonPath("$.details.email").exists()); + } + + @Test + void departmentAddressAndProfileFlowsWorkWithH2() throws Exception { + mockMvc.perform(post("/rest/Department/insert") + .contentType(MediaType.APPLICATION_JSON) + .content(departmentJson())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.name").value("Engineering")); + Department department = departmentRepository.findByName("Engineering").get(0); + + mockMvc.perform(post("/rest/Address/insert") + .contentType(MediaType.APPLICATION_JSON) + .content(addressJson(1))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].city").value("Bangalore")); + Address address = addressRepository.findByCity("Bangalore").get(0); + + mockMvc.perform(post("/rest/Profile/insert") + .contentType(MediaType.APPLICATION_JSON) + .content(profileJson(1))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.gender").value("Male")); + Profile profile = profileRepository.findByGender("Male").get(0); + + mockMvc.perform(get("/rest/Department/findbyname").param("name", "Engineering")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].address").value("Bangalore")); + + mockMvc.perform(post("/rest/Department/updatefloor") + .param("Id", department.getId().toString()) + .param("floor", "5")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.floor").value(5)); + + mockMvc.perform(get("/rest/Address/findbycity").param("city", "Bangalore")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].pin").value(560001)); + + mockMvc.perform(post("/rest/Address/updateaddress") + .param("Id", address.getId().toString()) + .param("address1", "Line 1") + .param("address2", "Line 2") + .param("city", "Mysore") + .param("state", "Karnataka") + .param("pin", "570001")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.city").value("Mysore")); + + mockMvc.perform(get("/rest/Profile/findbygender").param("gender", "Male")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].hobbies").value("Reading")); + + mockMvc.perform(post("/rest/Profile/updatehobbies") + .param("Id", profile.getId().toString()) + .param("hobbies", "Chess")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.hobbies").value("Chess")); + + mockMvc.perform(delete("/rest/Profile/delete").param("Id", profile.getId().toString())) + .andExpect(status().isOk()); + } + + @Test + void loginAndLogoutReportExpectedStatusCodes() throws Exception { + employeeRepository.save(sampleEmployee("login@example.com")); + + mockMvc.perform(post("/rest/Login/login") + .param("email", "login@example.com") + .param("password", "wrong")) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.status").value(false)) + .andExpect(jsonPath("$.employee").doesNotExist()); + + mockMvc.perform(post("/rest/Login/login") + .param("email", "login@example.com") + .param("password", "secret")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status").value(true)) + .andExpect(jsonPath("$.employee.email").value("login@example.com")) + .andExpect(jsonPath("$.employee.password").doesNotExist()); + + mockMvc.perform(post("/rest/Login/login") + .param("email", "login@example.com") + .param("password", "secret")) + .andExpect(status().isForbidden()) + .andExpect(jsonPath("$.message", containsString("already logged in"))); + + mockMvc.perform(post("/rest/Login/logout").param("email", "login@example.com")) + .andExpect(status().isOk()) + .andExpect(content().string("Logged Out")); + + mockMvc.perform(get("/rest/Login/findbyemail").param("email", "login@example.com")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.email").value("login@example.com")) + .andExpect(jsonPath("$.password").doesNotExist()); + } + + private Employee sampleEmployee(String email) { + Employee employee = new Employee(); + employee.setName("Test Employee"); + employee.setDesignation("Developer"); + employee.setSalary(50000); + employee.setDepId(1); + employee.setMobile(9876543210L); + employee.setEmail(email); + employee.setPassword("secret"); + employee.setStatus("Logged Out"); + employee.setAccountStatus("Activated"); + employee.setCreatedBy("test"); + employee.setCreatedAt("2026-05-10"); + return employee; + } + + private String employeeJson(String email) { + return "{" + + "\"name\":\"Test Employee\"," + + "\"designation\":\"Developer\"," + + "\"salary\":50000," + + "\"depId\":1," + + "\"mobile\":9876543210," + + "\"email\":\"" + email + "\"," + + "\"password\":\"secret\"," + + "\"status\":\"Logged Out\"," + + "\"accountStatus\":\"Activated\"," + + "\"createdBy\":\"test\"," + + "\"createdAt\":\"2026-05-10\"" + + "}"; + } + + private Department sampleDepartment() { + Department department = new Department(); + department.setName("Engineering"); + department.setAddress("Bangalore"); + department.setFloor(3); + department.setCreatedBy("test"); + department.setCreatedAt("2026-05-10"); + return department; + } + + private String departmentJson() { + return "{" + + "\"name\":\"Engineering\"," + + "\"address\":\"Bangalore\"," + + "\"floor\":3," + + "\"createdBy\":\"test\"," + + "\"createdAt\":\"2026-05-10\"" + + "}"; + } + + private Address sampleAddress(Integer empId) { + Address address = new Address(); + address.setAddress1("Street 1"); + address.setAddress2("Area 1"); + address.setCity("Bangalore"); + address.setState("Karnataka"); + address.setPIN(560001); + address.setEmpId(empId); + address.setCreatedBy("test"); + address.setCreatedAt("2026-05-10"); + return address; + } + + private String addressJson(Integer empId) { + return "{" + + "\"address1\":\"Street 1\"," + + "\"address2\":\"Area 1\"," + + "\"city\":\"Bangalore\"," + + "\"state\":\"Karnataka\"," + + "\"pin\":560001," + + "\"empId\":" + empId + "," + + "\"createdBy\":\"test\"," + + "\"createdAt\":\"2026-05-10\"" + + "}"; + } + + private Profile sampleProfile(Integer empId) { + Profile profile = new Profile(); + profile.setGender("Male"); + profile.setDOB("2000-01-01"); + profile.setHobbies("Reading"); + profile.setEmpId(empId); + profile.setCreatedBy("test"); + profile.setCreatedAt("2026-05-10"); + return profile; + } + + private String profileJson(Integer empId) { + return "{" + + "\"gender\":\"Male\"," + + "\"dob\":\"2000-01-01\"," + + "\"hobbies\":\"Reading\"," + + "\"empId\":" + empId + "," + + "\"createdBy\":\"test\"," + + "\"createdAt\":\"2026-05-10\"" + + "}"; + } +} diff --git a/src/test/java/com/hemant/db/service/EmployeeServiceTest.java b/src/test/java/com/hemant/db/service/EmployeeServiceTest.java new file mode 100644 index 0000000..cb6bd51 --- /dev/null +++ b/src/test/java/com/hemant/db/service/EmployeeServiceTest.java @@ -0,0 +1,66 @@ +package com.hemant.db.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import com.hemant.db.exception.ResourceNotFoundException; +import com.hemant.db.model.Employee; +import com.hemant.db.repository.EmployeeRepository; + +@SpringBootTest +@ActiveProfiles("test") +class EmployeeServiceTest { + @Autowired + private EmployeeService employeeService; + + @Autowired + private EmployeeRepository employeeRepository; + + @BeforeEach + void cleanDatabase() { + employeeRepository.deleteAll(); + } + + @Test + void createEmployeePersistsAndHidesDeactivatedRecordsFromList() { + Employee activeEmployee = sampleEmployee("active@example.com", "Activated"); + Employee deactivatedEmployee = sampleEmployee("inactive@example.com", "Deactivated"); + + Employee savedActiveEmployee = employeeService.createEmployee(activeEmployee); + employeeService.createEmployee(deactivatedEmployee); + + assertThat(savedActiveEmployee.getId()).isNotNull(); + assertThat(employeeService.getAllEmployees()) + .extracting(Employee::getEmail) + .containsExactly("active@example.com"); + } + + @Test + void updateMissingEmployeeThrowsNotFound() { + assertThatThrownBy(() -> employeeService.updateDesignation(999, "Manager")) + .isInstanceOf(ResourceNotFoundException.class) + .hasMessageContaining("Employee not found with id 999"); + } + + private Employee sampleEmployee(String email, String accountStatus) { + Employee employee = new Employee(); + employee.setName("Test Employee"); + employee.setDesignation("Developer"); + employee.setSalary(50000); + employee.setDepId(1); + employee.setMobile(9876543210L); + employee.setEmail(email); + employee.setPassword("secret"); + employee.setStatus("Logged Out"); + employee.setAccountStatus(accountStatus); + employee.setCreatedBy("test"); + employee.setCreatedAt("2026-05-10"); + return employee; + } +} diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml new file mode 100644 index 0000000..9d66a61 --- /dev/null +++ b/src/test/resources/application-test.yml @@ -0,0 +1,14 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:springboot_mysql_test;MODE=MySQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + username: sa + password: + jpa: + hibernate: + ddl-auto: create-drop + generate-ddl: true + show-sql: false + properties: + hibernate: + dialect: org.hibernate.dialect.H2Dialect