// Step 1: Create a Spring Boot Application
// File: Application.java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// Step 2: Create an Entity
// File: Employee.java
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String department;
@Column(nullable = false)
private double salary;
@OneToOne(mappedBy = "employee", cascade = CascadeType.ALL)
private Address address;
@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL)
private List<Project> projects;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "manager_id")
private Employee manager;
@ManyToMany
@JoinTable(
name = "employee_roles",
joinColumns = @JoinColumn(name = "employee_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles;
// Getters and setters
}
// File: Address.java
@Entity
@Table(name = "addresses")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String street;
@Column(nullable = false)
private String city;
@Column(nullable = false)
private String zipCode;
@OneToOne
@JoinColumn(name = "employee_id")
private Employee employee;
// Getters and setters
}
// File: Project.java
@Entity
@Table(name = "projects")
public class Project {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "employee_id")
private Employee employee;
// Getters and setters
}
// File: Role.java
@Entity
@Table(name = "roles")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String name;
@ManyToMany(mappedBy = "roles")
private Set<Employee> employees;
// Getters and setters
}
// Step 3: Create a Repository
// File: EmployeeRepository.java
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
// Derived query methods
List<Employee> findByDepartment(String department);
// Custom JPQL query
@Query("SELECT e FROM Employee e WHERE e.salary > :salary")
List<Employee> findEmployeesWithSalaryGreaterThan(@Param("salary") double salary);
// Native SQL query
@Query(value = "SELECT * FROM employees WHERE name LIKE %:name%", nativeQuery = true)
List<Employee> searchByName(@Param("name") String name);
// Transactional example
@Modifying
@Transactional
@Query("UPDATE Employee e SET e.salary = :salary WHERE e.id = :id")
int updateSalary(@Param("id") Long id, @Param("salary") double salary);
}
// File: AddressRepository.java
@Repository
public interface AddressRepository extends JpaRepository<Address, Long> {}
// File: ProjectRepository.java
@Repository
public interface ProjectRepository extends JpaRepository<Project, Long> {}
// File: RoleRepository.java
@Repository
public interface RoleRepository extends JpaRepository<Role, Long> {}
// Step 4: Create a Service
// File: EmployeeService.java
@Service
@Transactional
public class EmployeeService {
private final EmployeeRepository repository;
public EmployeeService(EmployeeRepository repository) {
this.repository = repository;
}
public List<Employee> getAllEmployees() {
return repository.findAll();
}
public Employee getEmployeeById(Long id) {
return repository.findById(id).orElseThrow(() -> new EntityNotFoundException("Employee not found"));
}
public Employee createEmployee(Employee employee) {
return repository.save(employee);
}
public Employee updateEmployee(Long id, Employee employeeDetails) {
Employee employee = getEmployeeById(id);
employee.setName(employeeDetails.getName());
employee.setDepartment(employeeDetails.getDepartment());
employee.setSalary(employeeDetails.getSalary());
return repository.save(employee);
}
public void deleteEmployee(Long id) {
if (!repository.existsById(id)) {
throw new EntityNotFoundException("Employee not found");
}
repository.deleteById(id);
}
public List<Employee> getByDepartment(String department) {
return repository.findByDepartment(department);
}
public List<Employee> findEmployeesWithSalaryGreaterThan(double salary) {
return repository.findEmployeesWithSalaryGreaterThan(salary);
}
public List<Employee> searchByName(String name) {
return repository.searchByName(name);
}
public int updateSalary(Long id, double salary) {
return repository.updateSalary(id, salary);
}
}
// Step 5: Create a Controller
// File: EmployeeController.java
@RestController
@RequestMapping("/api/employees")
public class EmployeeController {
private final EmployeeService service;
public EmployeeController(EmployeeService service) {
this.service = service;
}
// Create a new employee
@PostMapping
public ResponseEntity<Employee> createEmployee(@RequestBody Employee employee) {
return ResponseEntity.status(HttpStatus.CREATED).body(service.createEmployee(employee));
}
// Get all employees
@GetMapping
public List<Employee> getAllEmployees() {
return service.getAllEmployees();
}
// Get employee by ID
@GetMapping("/{id}")
public ResponseEntity<Employee> getEmployeeById(@PathVariable Long id) {
return ResponseEntity.ok(service.getEmployeeById(id));
}
// Update an employee
@PutMapping("/{id}")
public ResponseEntity<Employee> updateEmployee(@PathVariable Long id, @RequestBody Employee employeeDetails) {
return ResponseEntity.ok(service.updateEmployee(id, employeeDetails));
}
// Delete an employee
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteEmployee(@PathVariable Long id) {
service.deleteEmployee(id);
return ResponseEntity.noContent().build();
}
// Find employees by department
@GetMapping("/department")
public List<Employee> getByDepartment(@RequestParam String department) {
return service.getByDepartment(department);
}
// Find employees with salary greater than
@GetMapping("/salary")
public List<Employee> getBySalary(@RequestParam double salary) {
return service.findEmployeesWithSalaryGreaterThan(salary);
}
// Search by name
@GetMapping("/search")
public List<Employee> searchByName(@RequestParam String name) {
return service.searchByName(name);
}
// Update salary
@PatchMapping("/{id}/salary")
public ResponseEntity<String> updateSalary(@PathVariable Long id, @RequestParam double salary) {
int updated = service.updateSalary(id, salary);
return updated > 0 ? ResponseEntity.ok("Salary updated successfully") : ResponseEntity.status(HttpStatus.NOT_MODIFIED).body("Update failed");
}
}
// Step 6: Exception Handling
// File: GlobalExceptionHandler.java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<String> handleEntityNotFound(EntityNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
}
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleGeneralException(Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An unexpected error occurred: " + ex.getMessage());
}
}
// File: Custom Exceptions
public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(String message) {
super(message);
}
}
// Step 7: Configure In-Memory Database
// File: application.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true