Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Implementing Department and Employee Management Modules in Spring Boot

Tech 1

Application Architecture Overview

To build a maintainable enterprise application, the codebase is separated into distinct layers. The standard architecture for Spring Boot applications consists of the following tiers:

  • Controller Layer: Handles incoming HTTP requests, processes input parameters, invokes the service layer, and returns the response to the client. It acts as the entry point for the application.
  • Service Layer: Contains the business logic. It orchestrates data flow and transforms entities. This layer communicates with the data access layer and ensures transactional integrity.
  • Data Access Layer (Mapper/DAO): Responsible for interacting with the database. It performs CRUD operations using MyBatis or similar ORM tools.
  • Entity Layer (Model/POJO): Plain Old Java Objects that map directly to database tables. Each field in the class typically corresponds to a column in the respective table.

RESTful API Design Standards

The application adheres to RESTful principles for resource management. HTTP methods are mapped to specific actions:

  • GET: Retrieve resources.
  • POST: Create a new resource.
  • PUT: Update an existing resource.
  • DELETE: Remove a resource.

Resource endpoints are defined using plural nouns (e.g., /departments, /employees). All API responses are wrapped in a unified ResponseDTO structure to ensure consistent error handling and data formatting across the client-side.

Department Management Implementation

Retrieving Department List

The flow begins at the controller, which handles the GET request. Logging is implemented using the Slf4j annotation to track execution.

@RestController
@RequestMapping("/api/departments")
@RequiredArgsConstructor
public class DepartmentController {
    private final DepartmentService departmentService;
    
    @GetMapping
    public ResponseDTO<List<Department>> listAll() {
        log.info("Retrieving all departments");
        List<Department> deptList = departmentService.getAllDepartments();
        return ResponseDTO.success(deptList);
    }
}

The Service layer delegates the database call to the Mapper interface.

@Service
@RequiredArgsConstructor
public class DepartmentServiceImpl implements DepartmentService {
    private final DepartmentMapper departmentMapper;

    @Override
    public List<Department> getAllDepartments() {
        return departmentMapper.selectList();
    }
}

The Mapper uses MyBatis annotations to execute the SQL query.

@Mapper
public interface DepartmentMapper {
    @Select("SELECT id, name, create_time, update_time FROM tlias_dept")
    List<Department> selectList();
}

Deleting a Department

Deletion is triggered via a DELETE request. The controller accepts the department ID as a path variable.

@DeleteMapping("/{id}")
public ResponseDTO<Void> delete(@PathVariable Integer id) {
    log.info("Deleting department with id: {}", id);
    departmentService.removeDepartment(id);
    return ResponseDTO.success();
}

Adding a New Department

When creating a resource, the client sends a POST request with a JSON payload. The @RequestBody annotation binds the JSON body to a Java object. The Service layer is responsible for populating audit fields like createTime and updateTime before persistence.

@PostMapping
public ResponseDTO<Void> add(@RequestBody Department department) {
    log.info("Adding new department: {}", department.getName());
    departmentService.createDepartment(department);
    return ResponseDTO.success();
}

Updating a Department

Updates utilize the PUT method. The controller receives the full object, and the Mapper executes an update statement. The Controller path can be simplified using @RequestMapping at the class level, with specific mappings at the method level.

@PutMapping
public ResponseDTO<Void> update(@RequestBody Department department) {
    departmentService.modifyDepartment(department);
    return ResponseDTO.success();
}

Employee Management Implementation

The employee module introduces complexity through pagination and conditional filtering.

Pagination with PageHelper

Manual pagination requires calculating offsets and limits manually. To streamline this, the PageHelper plugin is integrated. It intercepts SQL queries and automatically appends pagination logic.

@GetMapping
public ResponseDTO<PageResult<Employee>> getPage(
    @RequestParam(defaultValue = "1") Integer page,
    @RequestParam(defaultValue = "10") Integer pageSize) {
    
    PageHelper.startPage(page, pageSize);
    List<Employee> list = employeeMapper.selectList();
    PageInfo<Employee> info = new PageInfo<>(list);
    
    PageResult<Employee> result = new PageResult<>(info.getTotal(), info.getList());
    return ResponseDTO.success(result);
}

Conditional Dynamic Queries

Searching requires filtering by name, gender, and date range. This is implemented using MyBatis Dynamic SQL in XML configuration. The Service layer sets the pagination parameters before invoking the mapper.

@GetMapping("/search")
public ResponseDTO<PageResult<Employee>> search(
    @RequestParam(defaultValue = "1") Integer page,
    @RequestParam(defaultValue = "10") Integer pageSize,
    String name,
    Short gender,
    @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
    @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {

    PageHelper.startPage(page, pageSize);
    List<Employee> list = employeeMapper.selectByCondition(name, gender, begin, end);
    Page<Employee> p = (Page<Employee>) list;
    
    return ResponseDTO.success(new PageResult<>(p.getTotal(), p.getResult()));
}

The corresponding Mapper XML uses <if> tags to conditionally append SQL clauses.

<select id="selectByCondition" resultType="Employee">
    SELECT * FROM tlias_emp
    <where>
        <if test="name != null and name != ''">
            AND name LIKE CONCAT('%', #{name}, '%')
        </if>
        <if test="gender != null">
            AND gender = #{gender}
        </if>
        <if test="begin != null and end != null">
            AND entrydate BETWEEN #{begin} AND #{end}
        </if>
    </where>
</select>

Bulk Operations

Bulk deletion accepts a list of IDs. The Mapper uses the <foreach> tag to generate the IN clause dynamically.

@DeleteMapping("/{ids}")
public ResponseDTO<Void> deleteBatch(@PathVariable List<Integer> ids) {
    employeeMapper.deleteBatch(ids);
    return ResponseDTO.success();
}
Tags: Spring Boot

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.