Skip to content

Commit 36aa8ea

Browse files
committed
feat: add TrainTypeDto and related endpoints for train type management
- Introduced TrainTypeDto for representing train type data with relevant fields. - Added new endpoints in AdminTrainController and TrainController for creating, updating, retrieving, and deleting train types. - Implemented TrainTypeMapper for converting between TrainType and TrainTypeDto. - Updated OpenAPI specifications to include new train type endpoints and schemas. - Enhanced unit tests to cover new functionalities for train type management.
1 parent a907202 commit 36aa8ea

File tree

13 files changed

+575
-247
lines changed

13 files changed

+575
-247
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,7 @@ components:
3434
# --- User DTO Schema ---
3535
UserDto:
3636
$ref: 'user/schemas.yaml#/components/schemas/UserDto'
37+
38+
# --- Train DTO Schema ---
39+
TrainTypeDto:
40+
$ref: 'train/schemas.yaml#/components/schemas/TrainTypeDto'
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package edu.fudan.common.client.dto.train;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
import lombok.ToString;
8+
9+
/**
10+
* Data transfer object for train type definitions.
11+
*/
12+
@Data
13+
@Builder
14+
@NoArgsConstructor
15+
@AllArgsConstructor
16+
@ToString
17+
public class TrainTypeDto {
18+
19+
/**
20+
* Unique identifier generated by the train service.
21+
*/
22+
private String id;
23+
24+
/**
25+
* Display name of the train type (e.g., G-series).
26+
*/
27+
private String name;
28+
29+
/**
30+
* Available seats in economy class.
31+
*/
32+
private Integer economyClass;
33+
34+
/**
35+
* Available seats in comfort class.
36+
*/
37+
private Integer confortClass;
38+
39+
/**
40+
* The average speed for this train type in km/h.
41+
*/
42+
private Integer averageSpeed;
43+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
components:
2+
schemas:
3+
TrainTypeDto:
4+
type: object
5+
description: Data transfer object describing a train type definition.
6+
properties:
7+
id:
8+
type: string
9+
description: Unique identifier generated by the train service.
10+
name:
11+
type: string
12+
description: Display name of the train type (e.g., G-series).
13+
economyClass:
14+
type: integer
15+
format: int32
16+
description: Available seats in economy class.
17+
confortClass:
18+
type: integer
19+
format: int32
20+
description: Available seats in comfort class.
21+
averageSpeed:
22+
type: integer
23+
format: int32
24+
description: Average speed for this train type in km/h.
25+

ts-train-service/pom.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,21 @@
4545
<groupId>jakarta.validation</groupId>
4646
<artifactId>jakarta.validation-api</artifactId>
4747
</dependency>
48+
<!-- Lombok -->
49+
<dependency>
50+
<groupId>org.projectlombok</groupId>
51+
<artifactId>lombok</artifactId>
52+
<optional>true</optional>
53+
</dependency>
54+
<dependency>
55+
<groupId>org.mapstruct</groupId>
56+
<artifactId>mapstruct</artifactId>
57+
</dependency>
58+
<dependency>
59+
<groupId>org.services</groupId>
60+
<artifactId>ts-client-sdk</artifactId>
61+
<version>0.1.0</version>
62+
</dependency>
4863
</dependencies>
4964
<build>
5065
<plugins>

ts-train-service/src/main/java/train/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
.authorizeRequests()
7171
.antMatchers("/api/v1/train/admin/**").hasRole(admin)
7272
.antMatchers("/api/v1/train/**").permitAll()
73-
.antMatchers(HttpMethod.POST, "/api/v1/train/trains").hasAnyRole(admin)
74-
.antMatchers(HttpMethod.PUT, "/api/v1/train/trains").hasAnyRole(admin)
75-
.antMatchers(HttpMethod.DELETE, "/api/v1/train/trains/*").hasAnyRole(admin)
7673
.antMatchers("/swagger-ui.html", "/webjars/**", "/images/**",
7774
"/configuration/**", "/swagger-resources/**", "/v2/**").permitAll()
7875
.anyRequest().authenticated()
Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,65 @@
11
package train.controller;
22

3-
import train.entity.TrainType;
3+
import edu.fudan.common.client.dto.train.TrainTypeDto;
44
import edu.fudan.common.util.Response;
5-
import org.slf4j.Logger;
6-
import org.slf4j.LoggerFactory;
5+
import lombok.extern.slf4j.Slf4j;
76
import org.springframework.beans.factory.annotation.Autowired;
87
import org.springframework.http.HttpHeaders;
98
import org.springframework.http.ResponseEntity;
10-
import org.springframework.web.bind.annotation.*;
9+
import org.springframework.web.bind.annotation.DeleteMapping;
10+
import org.springframework.web.bind.annotation.PathVariable;
11+
import org.springframework.web.bind.annotation.PostMapping;
12+
import org.springframework.web.bind.annotation.PutMapping;
13+
import org.springframework.web.bind.annotation.RequestBody;
14+
import org.springframework.web.bind.annotation.RequestHeader;
15+
import org.springframework.web.bind.annotation.RequestMapping;
16+
import org.springframework.web.bind.annotation.RestController;
17+
import train.entity.TrainType;
18+
import train.mapper.TrainTypeMapper;
1119
import train.service.TrainService;
1220

1321
import static org.springframework.http.ResponseEntity.ok;
1422

23+
@Slf4j
1524
@RestController
1625
@RequestMapping("/api/v1/train/admin")
1726
public class AdminTrainController {
1827

19-
private static final Logger LOGGER = LoggerFactory.getLogger(AdminTrainController.class);
20-
2128
@Autowired
2229
private TrainService trainService;
2330

24-
@GetMapping("/welcome")
25-
public String home(@RequestHeader HttpHeaders headers){
26-
return "Welcome to [ AdminTrain Service ] !";
31+
@Autowired
32+
private TrainTypeMapper trainTypeMapper;
33+
34+
@PostMapping("/trainTypes")
35+
public ResponseEntity<Response<Void>> addTrain(@RequestBody TrainTypeDto trainTypeDto,
36+
@RequestHeader HttpHeaders headers){
37+
log.info("[addTrain][Admin add train][name: {}]", trainTypeDto.getName());
38+
boolean created = trainService.create(toEntity(trainTypeDto), headers);
39+
return ok(buildVoidResponse(created, "exists"));
2740
}
2841

29-
@GetMapping("/trains")
30-
public ResponseEntity<Response> getAllTrains(@RequestHeader HttpHeaders headers){
31-
LOGGER.info("[getAllTrains][Admin get all trains]");
32-
return ok(new Response(1, "success", trainService.query(headers)));
42+
@PutMapping("/trainTypes")
43+
public ResponseEntity<Response<Void>> modifyTrain(@RequestBody TrainTypeDto trainTypeDto,
44+
@RequestHeader HttpHeaders headers){
45+
log.info("[modifyTrain][Admin modify train][id: {}]", trainTypeDto.getId());
46+
boolean updated = trainService.update(toEntity(trainTypeDto), headers);
47+
return ok(buildVoidResponse(updated, "not found"));
3348
}
3449

35-
@PostMapping("/trains")
36-
public ResponseEntity<Response> addTrain(@RequestBody TrainType trainType,@RequestHeader HttpHeaders headers){
37-
LOGGER.info("[addTrain][Admin add train][id: {}]",trainType.getId());
38-
boolean res = trainService.create(trainType, headers);
39-
return ok(new Response(res?1:0, res?"success":"exists", null));
50+
@DeleteMapping("/trainTypes/{trainTypeId}")
51+
public ResponseEntity<Response<Void>> deleteTrain(@PathVariable("trainTypeId") String trainTypeId,
52+
@RequestHeader HttpHeaders headers){
53+
log.info("[deleteTrain][Admin delete train][id: {}]", trainTypeId);
54+
boolean deleted = trainService.delete(trainTypeId, headers);
55+
return ok(buildVoidResponse(deleted, "not found"));
4056
}
4157

42-
@PutMapping("/trains")
43-
public ResponseEntity<Response> modifyTrain(@RequestBody TrainType trainType,@RequestHeader HttpHeaders headers){
44-
LOGGER.info("[modifyTrain][Admin modify train][id: {}]",trainType.getId());
45-
boolean res = trainService.update(trainType, headers);
46-
return ok(new Response(res?1:0, res?"success":"not found", null));
58+
private TrainType toEntity(TrainTypeDto dto) {
59+
return dto == null ? null : trainTypeMapper.toEntity(dto);
4760
}
4861

49-
@DeleteMapping("/trains/{trainId}")
50-
public ResponseEntity<Response> deleteTrain(@PathVariable String trainId,@RequestHeader HttpHeaders headers){
51-
LOGGER.info("[deleteTrain][Admin delete train][id: {}]",trainId);
52-
boolean res = trainService.delete(trainId, headers);
53-
return ok(new Response(res?1:0, res?"success":"not found", null));
62+
private Response<Void> buildVoidResponse(boolean success, String failureMsg) {
63+
return new Response<>(success ? 1 : 0, success ? "success" : failureMsg, null);
5464
}
5565
}
Lines changed: 40 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,78 @@
11
package train.controller;
22

3+
import edu.fudan.common.client.dto.train.TrainTypeDto;
34
import edu.fudan.common.util.Response;
4-
import org.slf4j.Logger;
5-
import org.slf4j.LoggerFactory;
5+
import lombok.extern.slf4j.Slf4j;
66
import org.springframework.beans.factory.annotation.Autowired;
77
import org.springframework.http.HttpEntity;
88
import org.springframework.http.HttpHeaders;
9-
import org.springframework.web.bind.annotation.*;
9+
import org.springframework.web.bind.annotation.GetMapping;
10+
import org.springframework.web.bind.annotation.PathVariable;
11+
import org.springframework.web.bind.annotation.PostMapping;
12+
import org.springframework.web.bind.annotation.RequestBody;
13+
import org.springframework.web.bind.annotation.RequestHeader;
14+
import org.springframework.web.bind.annotation.RequestMapping;
15+
import org.springframework.web.bind.annotation.RestController;
1016
import train.entity.TrainType;
17+
import train.mapper.TrainTypeMapper;
1118
import train.service.TrainService;
1219

1320
import java.util.List;
1421

1522
import static org.springframework.http.ResponseEntity.ok;
1623

17-
24+
@Slf4j
1825
@RestController
1926
@RequestMapping("/api/v1/train")
2027
public class TrainController {
2128

22-
2329
@Autowired
2430
private TrainService trainService;
2531

26-
private static final Logger LOGGER = LoggerFactory.getLogger(TrainController.class);
32+
@Autowired
33+
private TrainTypeMapper trainTypeMapper;
2734

28-
@GetMapping(path = "/trains/welcome")
35+
@GetMapping(path = "/welcome")
2936
public String home(@RequestHeader HttpHeaders headers) {
3037
return "Welcome to [ Train Service ] !";
3138
}
3239

33-
@CrossOrigin(origins = "*")
34-
@PostMapping(value = "/trains")
35-
public HttpEntity create(@RequestBody TrainType trainType, @RequestHeader HttpHeaders headers) {
36-
TrainController.LOGGER.info("[create][Create train][TrainTypeId: {}]",trainType.getId());
37-
boolean isCreateSuccess = trainService.create(trainType, headers);
38-
if (isCreateSuccess) {
39-
return ok(new Response(1, "create success", null));
40-
} else {
41-
return ok(new Response(0, "train type already exist", trainType));
42-
}
40+
@GetMapping(value = "/trainTypes")
41+
public HttpEntity<Response<List<TrainTypeDto>>> query(@RequestHeader HttpHeaders headers) {
42+
log.info("[query][Query train]");
43+
return ok(toListResponse(trainService.query(headers), "no content"));
4344
}
4445

45-
@CrossOrigin(origins = "*")
46-
@GetMapping(value = "/trains/{id}")
47-
public HttpEntity retrieve(@PathVariable String id, @RequestHeader HttpHeaders headers) {
48-
TrainController.LOGGER.info("[retrieve][Retrieve train][TrainTypeId: {}]",id);
49-
TrainType trainType = trainService.retrieve(id, headers);
50-
if (trainType == null) {
51-
return ok(new Response(0, "here is no TrainType with the trainType id: " + id, null));
52-
} else {
53-
return ok(new Response(1, "success", trainType));
54-
}
46+
@GetMapping(value = "/trainTypes/{id}")
47+
public HttpEntity<Response<TrainTypeDto>> retrieve(@PathVariable String id, @RequestHeader HttpHeaders headers) {
48+
log.info("[retrieve][Retrieve train][TrainTypeId: {}]", id);
49+
String msg = "here is no TrainType with the trainType id: " + id;
50+
return ok(toSingleResponse(trainService.retrieve(id, headers), msg));
5551
}
5652

57-
@CrossOrigin(origins = "*")
58-
@GetMapping(value = "/trains/byName/{name}")
59-
public HttpEntity retrieveByName(@PathVariable String name, @RequestHeader HttpHeaders headers) {
60-
TrainController.LOGGER.info("[retrieveByName][Retrieve train][TrainTypeName: {}]", name);
61-
TrainType trainType = trainService.retrieveByName(name, headers);
62-
if (trainType == null) {
63-
return ok(new Response(0, "here is no TrainType with the trainType name: " + name, null));
64-
} else {
65-
return ok(new Response(1, "success", trainType));
66-
}
53+
@GetMapping(value = "/trainTypes/byName/{name}")
54+
public HttpEntity<Response<TrainTypeDto>> retrieveByName(@PathVariable String name, @RequestHeader HttpHeaders headers) {
55+
log.info("[retrieveByName][Retrieve train][TrainTypeName: {}]", name);
56+
String msg = "here is no TrainType with the trainType name: " + name;
57+
return ok(toSingleResponse(trainService.retrieveByName(name, headers), msg));
6758
}
6859

69-
@CrossOrigin(origins = "*")
7060
@PostMapping(value = "/trains/byNames")
71-
public HttpEntity retrieveByName(@RequestBody List<String> names, @RequestHeader HttpHeaders headers) {
72-
TrainController.LOGGER.info("[retrieveByNames][Retrieve train][TrainTypeNames: {}]", names);
73-
List<TrainType> trainTypes = trainService.retrieveByNames(names, headers);
74-
if (trainTypes == null) {
75-
return ok(new Response(0, "here is no TrainTypes with the trainType names: " + names, null));
76-
} else {
77-
return ok(new Response(1, "success", trainTypes));
78-
}
79-
}
80-
81-
@CrossOrigin(origins = "*")
82-
@PutMapping(value = "/trains")
83-
public HttpEntity update(@RequestBody TrainType trainType, @RequestHeader HttpHeaders headers) {
84-
TrainController.LOGGER.info("[update][Update train][TrainTypeId: {}]",trainType.getId());
85-
boolean isUpdateSuccess = trainService.update(trainType, headers);
86-
if (isUpdateSuccess) {
87-
return ok(new Response(1, "update success", isUpdateSuccess));
88-
} else {
89-
return ok(new Response(0, "there is no trainType with the trainType id", isUpdateSuccess));
90-
}
61+
public HttpEntity<Response<List<TrainTypeDto>>> retrieveByName(@RequestBody List<String> names, @RequestHeader HttpHeaders headers) {
62+
log.info("[retrieveByNames][Retrieve train][TrainTypeNames: {}]", names);
63+
String msg = "here is no TrainTypes with the trainType names: " + names;
64+
return ok(toListResponse(trainService.retrieveByNames(names, headers), msg));
9165
}
9266

93-
@CrossOrigin(origins = "*")
94-
@DeleteMapping(value = "/trains/{id}")
95-
public HttpEntity delete(@PathVariable String id, @RequestHeader HttpHeaders headers) {
96-
TrainController.LOGGER.info("[delete][Delete train][TrainTypeId: {}]",id);
97-
boolean isDeleteSuccess = trainService.delete(id, headers);
98-
if (isDeleteSuccess) {
99-
return ok(new Response(1, "delete success", isDeleteSuccess));
100-
} else {
101-
return ok(new Response(0, "there is no train according to id", null));
102-
}
67+
private Response<List<TrainTypeDto>> toListResponse(List<TrainType> entities, String emptyMsg) {
68+
List<TrainTypeDto> payload = entities == null ? null : trainTypeMapper.toDtoList(entities);
69+
boolean hasData = payload != null && !payload.isEmpty();
70+
return new Response<>(hasData ? 1 : 0, hasData ? "success" : emptyMsg, payload);
10371
}
10472

105-
@CrossOrigin(origins = "*")
106-
@GetMapping(value = "/trains")
107-
public HttpEntity query(@RequestHeader HttpHeaders headers) {
108-
TrainController.LOGGER.info("[query][Query train]");
109-
List<TrainType> trainTypes = trainService.query(headers);
110-
if (trainTypes != null && !trainTypes.isEmpty()) {
111-
return ok(new Response(1, "success", trainTypes));
112-
} else {
113-
return ok(new Response(0, "no content", trainTypes));
114-
}
73+
private Response<TrainTypeDto> toSingleResponse(TrainType entity, String notFoundMsg) {
74+
TrainTypeDto payload = entity == null ? null : trainTypeMapper.toDto(entity);
75+
boolean hasData = payload != null;
76+
return new Response<>(hasData ? 1 : 0, hasData ? "success" : notFoundMsg, payload);
11577
}
11678
}

ts-train-service/src/main/java/train/entity/TrainType.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,4 @@ public TrainType(String name, int economyClass, int confortClass, int averageSpe
5151
this.confortClass = confortClass;
5252
this.averageSpeed = averageSpeed;
5353
}
54-
5554
}

0 commit comments

Comments
 (0)