Skip to content

Commit db6f094

Browse files
committed
feat: implement Station management features in the station service
- Introduced StationDto for representing station data with relevant fields. - Added public and administrative endpoints for creating, updating, retrieving, and deleting stations in StationController and AdminStationController. - Implemented StationMapper for converting between Station and StationDto. - Updated OpenAPI specifications to include new station management endpoints and schemas. - Enhanced unit tests for AdminStationController and StationController to cover new functionalities.
1 parent 36aa8ea commit db6f094

File tree

15 files changed

+814
-308
lines changed

15 files changed

+814
-308
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package edu.fudan.common.client;
2+
3+
import edu.fudan.common.client.dto.station.StationDto;
4+
import edu.fudan.common.util.Response;
5+
import java.util.List;
6+
import java.util.Map;
7+
import lombok.extern.slf4j.Slf4j;
8+
import org.springframework.core.ParameterizedTypeReference;
9+
import org.springframework.http.HttpHeaders;
10+
import org.springframework.http.HttpMethod;
11+
import org.springframework.stereotype.Component;
12+
13+
@Slf4j
14+
@Component
15+
public class StationClient extends BaseClient {
16+
private static final String SERVICE_NAME = "ts-station-service";
17+
private static final String BASE_URL = "/api/v1/station";
18+
19+
private String getServiceUrl() {
20+
return "http://" + SERVICE_NAME;
21+
}
22+
23+
private String getBaseUrl() {
24+
return getServiceUrl() + BASE_URL;
25+
}
26+
27+
/* ---------- public station endpoints ---------- */
28+
29+
public Response<List<StationDto>> getAllStations(HttpHeaders headers) {
30+
return exchange(getBaseUrl() + "/stations", HttpMethod.GET, null, headers,
31+
new ParameterizedTypeReference<Response<List<StationDto>>>() {});
32+
}
33+
34+
public Response<String> getStationIdByName(String stationName, HttpHeaders headers) {
35+
return exchange(getBaseUrl() + "/stations/id/" + stationName, HttpMethod.GET, null, headers,
36+
new ParameterizedTypeReference<Response<String>>() {});
37+
}
38+
39+
public Response<Map<String, String>> getStationIdsByNames(List<String> stationNames,
40+
HttpHeaders headers) {
41+
return exchange(getBaseUrl() + "/stations/idlist", HttpMethod.POST, stationNames, headers,
42+
new ParameterizedTypeReference<Response<Map<String, String>>>() {});
43+
}
44+
45+
public Response<String> getStationNameById(String stationId, HttpHeaders headers) {
46+
return exchange(getBaseUrl() + "/stations/name/" + stationId, HttpMethod.GET, null, headers,
47+
new ParameterizedTypeReference<Response<String>>() {});
48+
}
49+
50+
public Response<List<String>> getStationNamesByIds(List<String> stationIds, HttpHeaders headers) {
51+
return exchange(getBaseUrl() + "/stations/namelist", HttpMethod.POST, stationIds, headers,
52+
new ParameterizedTypeReference<Response<List<String>>>() {});
53+
}
54+
55+
/* ---------- admin station endpoints ---------- */
56+
57+
public Response<StationDto> adminCreateStation(StationDto stationDto, HttpHeaders headers) {
58+
return exchange(getBaseUrl() + "/admin/stations", HttpMethod.POST, stationDto, headers,
59+
new ParameterizedTypeReference<Response<StationDto>>() {});
60+
}
61+
62+
public Response<StationDto> adminUpdateStation(StationDto stationDto, HttpHeaders headers) {
63+
return exchange(getBaseUrl() + "/admin/stations", HttpMethod.PUT, stationDto, headers,
64+
new ParameterizedTypeReference<Response<StationDto>>() {});
65+
}
66+
67+
public Response<StationDto> adminDeleteStation(String stationId, HttpHeaders headers) {
68+
return exchange(getBaseUrl() + "/admin/stations/" + stationId, HttpMethod.DELETE, null, headers,
69+
new ParameterizedTypeReference<Response<StationDto>>() {});
70+
}
71+
}
72+

ts-client-sdk/src/main/java/edu/fudan/common/client/dto/schemas.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,8 @@ components:
3737

3838
# --- Train DTO Schema ---
3939
TrainTypeDto:
40-
$ref: 'train/schemas.yaml#/components/schemas/TrainTypeDto'
40+
$ref: 'train/schemas.yaml#/components/schemas/TrainTypeDto'
41+
42+
# --- Station DTO Schema ---
43+
StationDto:
44+
$ref: 'station/schemas.yaml#/components/schemas/StationDto'
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package edu.fudan.common.client.dto.station;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
import lombok.ToString;
8+
9+
/**
10+
* Station data transfer object mirroring the station service entity.
11+
*/
12+
@Data
13+
@Builder
14+
@AllArgsConstructor
15+
@NoArgsConstructor
16+
@ToString
17+
public class StationDto {
18+
19+
/**
20+
* Unique identifier generated by the station service.
21+
*/
22+
private String id;
23+
24+
/**
25+
* Lowercase, whitespace-stripped station name.
26+
*/
27+
private String name;
28+
29+
/**
30+
* Planned stay time (in minutes) for trains at this station.
31+
*/
32+
private int stayTime;
33+
}
34+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
components:
2+
schemas:
3+
StationDto:
4+
type: object
5+
description: Data transfer object that mirrors the station entity exposed by ts-station-service.
6+
properties:
7+
id:
8+
type: string
9+
description: Unique identifier generated by the station service.
10+
name:
11+
type: string
12+
description: Lowercase, whitespace-stripped station name.
13+
stayTime:
14+
type: integer
15+
format: int32
16+
description: Planned dwell time (minutes) at this station.
17+

ts-station-service/pom.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@
4646
<groupId>jakarta.validation</groupId>
4747
<artifactId>jakarta.validation-api</artifactId>
4848
</dependency>
49+
<dependency>
50+
<groupId>org.hibernate.validator</groupId>
51+
<artifactId>hibernate-validator</artifactId>
52+
</dependency>
53+
<dependency>
54+
<groupId>org.mapstruct</groupId>
55+
<artifactId>mapstruct</artifactId>
56+
</dependency>
57+
<dependency>
58+
<groupId>org.services</groupId>
59+
<artifactId>ts-client-sdk</artifactId>
60+
<version>0.1.0</version>
61+
</dependency>
4962
</dependencies>
5063

5164
<build>

ts-station-service/src/main/java/fdse/microservice/config/SecurityConfig.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,6 @@ protected void configure(HttpSecurity httpSecurity) throws Exception {
7070
.and()
7171
.authorizeRequests()
7272
.antMatchers("/api/v1/station/admin/**").hasRole(admin)
73-
.antMatchers(HttpMethod.POST, stations).hasAnyRole(admin)
74-
.antMatchers(HttpMethod.PUT, stations).hasAnyRole(admin)
75-
.antMatchers(HttpMethod.DELETE, stations).hasAnyRole(admin)
7673
.antMatchers("/api/v1/station/**").permitAll()
7774
.antMatchers("/swagger-ui.html", "/webjars/**", "/images/**",
7875
"/configuration/**", "/swagger-resources/**", "/v2/**").permitAll()
Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,57 @@
11
package fdse.microservice.controller;
22

3-
import fdse.microservice.entity.Station;
3+
import edu.fudan.common.client.dto.station.StationDto;
44
import edu.fudan.common.util.Response;
5+
import fdse.microservice.entity.Station;
6+
import fdse.microservice.mapper.StationMapper;
57
import fdse.microservice.service.StationService;
6-
import org.slf4j.Logger;
7-
import org.slf4j.LoggerFactory;
8-
import org.springframework.beans.factory.annotation.Autowired;
98
import org.springframework.http.HttpHeaders;
9+
import org.springframework.http.HttpStatus;
1010
import org.springframework.http.ResponseEntity;
1111
import org.springframework.web.bind.annotation.*;
1212

13+
import lombok.RequiredArgsConstructor;
14+
import lombok.extern.slf4j.Slf4j;
1315
import static org.springframework.http.ResponseEntity.ok;
1416

17+
@Slf4j
1518
@RestController
1619
@RequestMapping("/api/v1/station/admin")
20+
@RequiredArgsConstructor
1721
public class AdminStationController {
1822

19-
private static final Logger LOGGER = LoggerFactory.getLogger(AdminStationController.class);
23+
private final StationService stationService;
2024

21-
@Autowired
22-
private StationService stationService;
23-
24-
@GetMapping("/welcome")
25-
public String home(@RequestHeader HttpHeaders headers){
26-
return "Welcome to [ AdminStation Service ] !";
27-
}
25+
private final StationMapper stationMapper;
2826

29-
@GetMapping("/stations")
30-
public ResponseEntity<Response> getAllStations(@RequestHeader HttpHeaders headers){
31-
LOGGER.info("[getAllStations][Admin get all stations]");
32-
return ok(stationService.query(headers));
27+
private ResponseEntity<Response<StationDto>> respond(Response<Station> response) {
28+
return ok(stationMapper.toDtoResponse(response));
3329
}
3430

3531
@PostMapping("/stations")
36-
public ResponseEntity<Response> addStation(@RequestBody Station station,@RequestHeader HttpHeaders headers){
37-
LOGGER.info("[addStation][Admin add station][id: {}]",station.getId());
38-
return ok(stationService.create(station, headers));
32+
public ResponseEntity<Response<StationDto>> addStation(@RequestBody StationDto stationDto,
33+
@RequestHeader HttpHeaders headers) {
34+
log.info("[addStation][Admin add station][station: {}]", stationDto);
35+
if (stationDto.getName().isEmpty()) {
36+
return new ResponseEntity<>(new Response<>(0, "Name not specify", null), HttpStatus.BAD_REQUEST);
37+
}
38+
return respond(stationService.create(stationMapper.toEntity(stationDto), headers));
3939
}
4040

4141
@PutMapping("/stations")
42-
public ResponseEntity<Response> modifyStation(@RequestBody Station station,@RequestHeader HttpHeaders headers){
43-
LOGGER.info("[modifyStation][Admin modify station][id: {}]",station.getId());
44-
return ok(stationService.update(station, headers));
42+
public ResponseEntity<Response<StationDto>> modifyStation(@RequestBody StationDto stationDto,
43+
@RequestHeader HttpHeaders headers) {
44+
log.info("[modifyStation][Admin modify station][id: {}]", stationDto.getId());
45+
if (stationDto.getId().isEmpty()) {
46+
return new ResponseEntity<>(new Response<>(0, "Id not specify", null), HttpStatus.BAD_REQUEST);
47+
}
48+
return respond(stationService.update(stationMapper.toEntity(stationDto), headers));
4549
}
4650

4751
@DeleteMapping("/stations/{stationId}")
48-
public ResponseEntity<Response> deleteStation(@PathVariable String stationId,@RequestHeader HttpHeaders headers){
49-
LOGGER.info("[deleteStation][Admin delete station][id: {}]",stationId);
50-
return ok(stationService.delete(stationId, headers));
52+
public ResponseEntity<Response<StationDto>> deleteStation(@PathVariable String stationId,
53+
@RequestHeader HttpHeaders headers) {
54+
log.info("[deleteStation][Admin delete station][id: {}]", stationId);
55+
return respond(stationService.delete(stationId, headers));
5156
}
5257
}

ts-station-service/src/main/java/fdse/microservice/controller/StationController.java

Lines changed: 19 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,69 @@
11
package fdse.microservice.controller;
22

3+
import edu.fudan.common.client.dto.station.StationDto;
34
import edu.fudan.common.util.Response;
4-
import fdse.microservice.entity.*;
5+
import fdse.microservice.mapper.StationMapper;
56
import fdse.microservice.service.StationService;
6-
import org.slf4j.Logger;
7-
import org.slf4j.LoggerFactory;
8-
import org.springframework.beans.factory.annotation.Autowired;
9-
import org.springframework.http.HttpEntity;
107
import org.springframework.http.HttpHeaders;
11-
import org.springframework.http.HttpStatus;
128
import org.springframework.http.ResponseEntity;
139
import org.springframework.web.bind.annotation.*;
1410

1511
import java.util.List;
12+
import java.util.Map;
1613

14+
import lombok.RequiredArgsConstructor;
15+
import lombok.extern.slf4j.Slf4j;
1716
import static org.springframework.http.ResponseEntity.ok;
1817

18+
@Slf4j
1919
@RestController
2020
@RequestMapping("/api/v1/station")
21+
@RequiredArgsConstructor
2122
public class StationController {
2223

23-
@Autowired
24-
private StationService stationService;
24+
private final StationService stationService;
2525

26-
private static final Logger LOGGER = LoggerFactory.getLogger(StationController.class);
26+
private final StationMapper stationMapper;
2727

2828
@GetMapping(path = "/welcome")
2929
public String home(@RequestHeader HttpHeaders headers) {
3030
return "Welcome to [ Station Service ] !";
3131
}
3232

3333
@GetMapping(value = "/stations")
34-
public HttpEntity query(@RequestHeader HttpHeaders headers) {
35-
return ok(stationService.query(headers));
34+
public ResponseEntity<Response<List<StationDto>>> query(@RequestHeader HttpHeaders headers) {
35+
return ok(stationMapper.toDtoListResponse(stationService.query(headers)));
3636
}
3737

38-
@PostMapping(value = "/stations")
39-
public ResponseEntity<Response> create(@RequestBody Station station, @RequestHeader HttpHeaders headers) {
40-
StationController.LOGGER.info("[create][Create station][name: {}]",station.getName());
41-
return new ResponseEntity<>(stationService.create(station, headers), HttpStatus.CREATED);
42-
}
43-
44-
@PutMapping(value = "/stations")
45-
public HttpEntity update(@RequestBody Station station, @RequestHeader HttpHeaders headers) {
46-
StationController.LOGGER.info("[update][Update station][StationId: {}]",station.getId());
47-
return ok(stationService.update(station, headers));
48-
}
49-
50-
@DeleteMapping(value = "/stations/{stationsId}")
51-
public ResponseEntity<Response> delete(@PathVariable String stationsId, @RequestHeader HttpHeaders headers) {
52-
StationController.LOGGER.info("[delete][Delete station][StationId: {}]",stationsId);
53-
return ok(stationService.delete(stationsId, headers));
54-
}
55-
56-
57-
5838
// according to station name ---> query station id
5939
@GetMapping(value = "/stations/id/{stationNameForId}")
60-
public HttpEntity queryForStationId(@PathVariable(value = "stationNameForId")
40+
public ResponseEntity<Response<String>> queryForStationId(@PathVariable(value = "stationNameForId")
6141
String stationName, @RequestHeader HttpHeaders headers) {
6242
// string
63-
StationController.LOGGER.info("[queryForId][Query for station id][StationName: {}]",stationName);
43+
log.info("[queryForId][Query for station id][StationName: {}]",stationName);
6444
return ok(stationService.queryForId(stationName, headers));
6545
}
6646

6747
// according to station name list ---> query all station ids
68-
@CrossOrigin(origins = "*")
6948
@PostMapping(value = "/stations/idlist")
70-
public HttpEntity queryForIdBatch(@RequestBody List<String> stationNameList, @RequestHeader HttpHeaders headers) {
71-
StationController.LOGGER.info("[queryForIdBatch][Query stations for id batch][StationNameNumbers: {}]",stationNameList.size());
49+
public ResponseEntity<Response<Map<String, String>>> queryForIdBatch(@RequestBody List<String> stationNameList, @RequestHeader HttpHeaders headers) {
50+
log.info("[queryForIdBatch][Query stations for id batch][StationNameNumbers: {}]",stationNameList.size());
7251
return ok(stationService.queryForIdBatch(stationNameList, headers));
7352
}
7453

7554
// according to station id ---> query station name
76-
@CrossOrigin(origins = "*")
7755
@GetMapping(value = "/stations/name/{stationIdForName}")
78-
public HttpEntity queryById(@PathVariable(value = "stationIdForName")
56+
public ResponseEntity<Response<String>> queryById(@PathVariable(value = "stationIdForName")
7957
String stationId, @RequestHeader HttpHeaders headers) {
80-
StationController.LOGGER.info("[queryById][Query stations By Id][Id: {}]", stationId);
58+
log.info("[queryById][Query stations By Id][Id: {}]", stationId);
8159
// string
8260
return ok(stationService.queryById(stationId, headers));
8361
}
8462

8563
// according to station id list ---> query all station names
86-
@CrossOrigin(origins = "*")
8764
@PostMapping(value = "/stations/namelist")
88-
public HttpEntity queryForNameBatch(@RequestBody List<String> stationIdList, @RequestHeader HttpHeaders headers) {
89-
StationController.LOGGER.info("[queryByIdBatch][Query stations for name batch][StationIdNumbers: {}]",stationIdList.size());
65+
public ResponseEntity<Response<List<String>>> queryForNameBatch(@RequestBody List<String> stationIdList, @RequestHeader HttpHeaders headers) {
66+
log.info("[queryByIdBatch][Query stations for name batch][StationIdNumbers: {}]",stationIdList.size());
9067
return ok(stationService.queryByIdBatch(stationIdList, headers));
9168
}
9269

0 commit comments

Comments
 (0)