You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Spring Boot+REST+Hibernate实现获取指定国家的所有城市

Alright, let's break down how to build the feature to fetch all cities for a specific country using Spring Boot, REST, and Hibernate, working with your existing entity classes.

实现指定国家的所有城市查询功能

We'll split this into three standard Spring Boot layers to keep the code clean and maintainable: Repository (Data Access), Service (Business Logic), and REST Controller (API Endpoint).

1. Data Access Layer: City Repository

First, create a Spring Data JPA repository for the City entity, adding a method to query cities by their associated country ID. Spring Data will auto-generate the SQL for this method.

import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;

public interface CityRepository extends JpaRepository<City, Long> {
    // Fetch all cities linked to a specific country ID
    List<City> findByCountryId(Long countryId);
}

You'll also need a basic repository for the Country entity to validate the country exists before fetching cities:

import org.springframework.data.jpa.repository.JpaRepository;

public interface CountryRepository extends JpaRepository<Country, Long> {
}

2. Business Logic Layer: City Service

Wrap the data access with a service layer to add validation and business rules (like checking if the requested country actually exists).

import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;

@Service
public class CityService {

    private final CityRepository cityRepository;
    private final CountryRepository countryRepository;

    // Constructor-based dependency injection (preferred over @Autowired)
    public CityService(CityRepository cityRepository, CountryRepository countryRepository) {
        this.cityRepository = cityRepository;
        this.countryRepository = countryRepository;
    }

    public List<City> getCitiesByCountryId(Long countryId) {
        // Validate the country exists first
        Optional<Country> country = countryRepository.findById(countryId);
        if (country.isEmpty()) {
            // For production, use a custom exception like CountryNotFoundException instead of RuntimeException
            throw new RuntimeException("Country with ID " + countryId + " does not exist");
        }
        return cityRepository.findByCountryId(countryId);
    }
}

3. REST Controller: Expose the API Endpoint

Create a controller to expose the endpoint that clients will call to get cities for a country.

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
@RequestMapping("/api/countries")
public class CountryCityController {

    private final CityService cityService;

    public CountryCityController(CityService cityService) {
        this.cityService = cityService;
    }

    // Endpoint: GET /api/countries/{countryId}/cities
    @GetMapping("/{countryId}/cities")
    public ResponseEntity<List<City>> getCitiesForCountry(@PathVariable Long countryId) {
        List<City> cities = cityService.getCitiesByCountryId(countryId);
        return ResponseEntity.ok(cities);
    }
}

4. Optional: Fixing Serialization Issues

Your City entity uses @JsonIgnore on the country field, which means the country data won't be included in the JSON response. If you want to return partial country details (like the country name) without causing circular serialization issues, use a DTO (Data Transfer Object):

Create a City Response DTO

public class CityResponseDTO {
    private Long id;
    private String name;
    private String countryName;

    // Map City entity to DTO
    public CityResponseDTO(City city) {
        this.id = city.getId();
        this.name = city.getName();
        this.countryName = city.getCountry().getName();
    }

    // Getters (setters optional unless you need them)
    public Long getId() { return id; }
    public String getName() { return name; }
    public String getCountryName() { return countryName; }
}

Update the Service to Return DTOs

public List<CityResponseDTO> getCitiesByCountryId(Long countryId) {
    Optional<Country> country = countryRepository.findById(countryId);
    if (country.isEmpty()) {
        throw new RuntimeException("Country with ID " + countryId + " does not exist");
    }
    return cityRepository.findByCountryId(countryId)
            .stream()
            .map(CityResponseDTO::new)
            .toList();
}

Update the Controller

@GetMapping("/{countryId}/cities")
public ResponseEntity<List<CityResponseDTO>> getCitiesForCountry(@PathVariable Long countryId) {
    List<CityResponseDTO> cities = cityService.getCitiesByCountryId(countryId);
    return ResponseEntity.ok(cities);
}

内容的提问来源于stack exchange,提问作者Manu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:50:11