spring boot 完整版规范工程代码(SpringBoot + Spring Data JPA + Service 分层 + DTO)

 

 

前端 ↔ DTO ↔ Controller ↔ Service ↔ Repository ↔ Entity(数据库)
 
核心规则:
  1. Entity:绑定数据库,绝不直接返回前端
  2. DTO:专门用于接口传输,隔离敏感字段
  3. Controller 只和 DTO 打交道
  4. Service 内部做 DTO ↔ Entity 转换(Mapper 映射逻辑)

一、包结构

plaintext
 
 
com.eazybytes.jobportal
├─ JobportalApplication 启动类
├─ entity
│   └─ Company.java          // JPA数据库实体
├─ dto
│   └─ CompanyDTO.java       // 对外传输DTO(无@Entity)
├─ repository
│   └─ CompanyRepository.java
├─ service
│   ├─ ICompanyService.java
│   └─ impl
│       └─ CompanyServiceImpl.java
└─ controller
    └─ CompanyController.java
 

1)Entity 实体:Company.java(映射数据库表)

java
 
运行
 
 
package com.eazybytes.jobportal.entity;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "company")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Company {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private String description;
    // 假设存在敏感字段!不希望暴露给前端
    private String adminPhone;
}
 

 

2)DTO 对象:CompanyDTO.java(给前端使用)

⚠️ 不加 @Entity!不和数据库绑定,只保留前端需要字段
java
 
运行
 
 
package com.eazybytes.jobportal.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class CompanyDTO {
    private Integer id;
    private String name;
    private String description;
    // 注意:没有 adminPhone 敏感字段!
}
 

 

3)Repository 持久层

java
 
运行
 
 
package com.eazybytes.jobportal.repository;

import com.eazybytes.jobportal.entity.Company;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CompanyRepository extends JpaRepository<Company, Integer> {
    // 仅数据库操作
}
 

 

4)Service 接口

❗注意:Service 方法出入参全部使用 DTO,不再向外暴露 Entity
java
 
运行
 
 
package com.eazybytes.jobportal.service;

import com.eazybytes.jobportal.dto.CompanyDTO;
import java.util.List;

public interface ICompanyService {
    List<CompanyDTO> getAllCompanies();
    CompanyDTO getCompanyById(Integer id);
    CompanyDTO createCompany(CompanyDTO dto);
}
 

 

5)Service 实现类【重点:在这里写转换逻辑 Mapper Logic】

java
 
运行
 
 
package com.eazybytes.jobportal.service.impl;

import com.eazybytes.jobportal.dto.CompanyDTO;
import com.eazybytes.jobportal.entity.Company;
import com.eazybytes.jobportal.repository.CompanyRepository;
import com.eazybytes.jobportal.service.ICompanyService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CompanyServiceImpl implements ICompanyService {

    private final CompanyRepository companyRepository;

    // 构造器注入(官方推荐)
    public CompanyServiceImpl(CompanyRepository companyRepository) {
        this.companyRepository = companyRepository;
    }

    @Override
    public List<CompanyDTO> getAllCompanies() {
        // 1. 查询数据库,得到Entity列表
        List<Company> entityList = companyRepository.findAll();

        // 2. Mapper映射:Entity → DTO
        return entityList.stream().map(entity -> {
            CompanyDTO dto = new CompanyDTO();
            dto.setId(entity.getId());
            dto.setName(entity.getName());
            dto.setDescription(entity.getDescription());
            // 敏感字段adminPhone直接忽略,不传给前端
            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public CompanyDTO getCompanyById(Integer id) {
        Company entity = companyRepository.findById(id).orElse(null);
        if (entity == null) return null;

        // entity转dto
        CompanyDTO dto = new CompanyDTO();
        dto.setId(entity.getId());
        dto.setName(entity.getName());
        dto.setDescription(entity.getDescription());
        return dto;
    }

    @Override
    public CompanyDTO createCompany(CompanyDTO dto) {
        // DTO → Entity:接收前端参数转为数据库实体
        Company entity = new Company();
        entity.setName(dto.getName());
        entity.setDescription(dto.getDescription());
        entity.setAdminPhone("内部管理员号码"); // 后端内部填充敏感数据

        Company savedEntity = companyRepository.save(entity);

        // 保存完成,再转回DTO返回前端
        CompanyDTO resultDto = new CompanyDTO();
        resultDto.setId(savedEntity.getId());
        resultDto.setName(savedEntity.getName());
        resultDto.setDescription(savedEntity.getDescription());
        return resultDto;
    }
}

 

 

6)Controller(只和 DTO 交互,完全看不到 Entity)

java
 
运行
 
 
package com.eazybytes.jobportal.controller;

import com.eazybytes.jobportal.dto.CompanyDTO;
import com.eazybytes.jobportal.service.ICompanyService;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/company")
public class CompanyController {

    private final ICompanyService companyService;

    public CompanyController(ICompanyService companyService) {
        this.companyService = companyService;
    }

    @GetMapping
    public List<CompanyDTO> getAll() {
        return companyService.getAllCompanies();
    }

    @GetMapping("/{id}")
    public CompanyDTO getById(@PathVariable Integer id) {
        return companyService.getCompanyById(id);
    }

    @PostMapping
    public CompanyDTO add(@RequestBody CompanyDTO companyDTO) {
        return companyService.createCompany(companyDTO);
    }
}
 

 

二、完整数据流对照你那张 DTO 示意图

  1. 前端调用接口 → 传入CompanyDTO
  2. Controller → 调用 Service
  3. Service:DTO → Entity,调用 Repository 保存数据库
  4. 查询时:Repository 拿到Company(Entity)
  5. Service 内部做映射(Mapper Logic):Entity → DTO
  6. DTO 返回前端,敏感字段 adminPhone 直接被过滤

 

posted @ 2026-07-30 16:02  漫漫长路</>  阅读(14)  评论(0)    收藏  举报