This is the 13th day of my participation in the First Challenge 2022
Custom return HTTP status code
When a browser enters a URL, the browser sends a request to the server. Before the browser receives and displays the response, the server returns a response header containing the HTTP status code. A dynamic code is an identifier that indicates whether the status of the current response has succeeded or failed or that other operations need to be performed.
Common HTTP status codes include 200, 302, 404, and 500
There are five types of HTTP status codes. The first digit of an HTTP status code indicates the type of the status code:
- 1xx: The server receives a request from the client and needs the client to continue operations
- 2xx: The request succeeded
- 3xx: redirect, further action is required to complete the request
- 4xx: An error occurs on the client or in the request
- 5xx: Service area error, request processing error
When we write programs based on Spring MVC, we do not define the response status code, because Spring MVC has defined the response code in the framework, there is no need to define the response code when writing business code, of course, Spring MVC also supports custom status code
The following scenarios require custom return status codes
- Sends a specific error code for unacceptable error types
- Client customization requirements
There are several ways to customize the return status code in Spring MVC:
- Use ResponseEntity to represent the status code, header information, and response body
- The @responseStatus annotation on the Controller class or exception class identifies the response code and returns the set response code when the method throws the exception
- Use @ControllerAdvice or @RestControllerAdvice to identify an exception handling class, and @ExceptionHanlder to identify an exception handling method that defines the return code and response body of the exception class
Create a new project, spring_mvC_traps, and add maven dependencies
<modelVersion>4.0. 0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.63.</version> <relativePath/> <! -- lookup parent from repository --> </parent> <groupId>com.citi</groupId> <artifactId>spring-mvc-traps</artifactId> <version>0.01.-SNAPSHOT</version>
<name>spring-traps</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Copy the code
Add the startup application main program
@SpringBootApplication
public class TrapsApplication {
public static void main(String[] args) { SpringApplication.run(TrapsApplication.class,args); }}Copy the code
ResponseEntity implements a custom HTTP status code
@RestController
@RequestMapping("/tesla")
public class TeslaController {
@GetMapping("/first")
public ResponseEntity<CommonResponse<String>> cyber(){
CommonResponse<String> result = new CommonResponse<>(0."");
result.setData("Cyber");
// Customize the HTTP response code
return newResponseEntity<>(result, HttpStatus.BAD_REQUEST); }}Copy the code
Use the REST Client plug-in of IDEA to initiate an HTTP request and create spring_mvc_traps. HTTP in the resources directory to add an HTTP request
###
GET http://localhost:8080/tesla/first
Accept: application/json
Copy the code
To start the service, click the start button to the left of the spring_mvc_traps. HTTP file to make an HTTP request
The response header is set to 400, the enumerated value of BAD_REQUEST.
@ ResponseStatus annotations
Take a look at the @responseStatus annotation
The @responseStatus annotation, which can be annotated on a class or a method, has three properties, value and code, which represent HTTP status. By default, INTERAL_SERVER_ERROR is 500. The reason attribute indicates the reason and is empty by default
Create a new common package and add a CommonException
@responseStatus (value = httpstatus.bad_request, reason = "error ")
public class CommonException extends RuntimeException{}Copy the code
New method in TeslaController
@GetMapping("/second")
public CommonResponse<String> model3(a){
throw new CommonException();
}
Copy the code
Add request methods to spring_mvc_traps.http
GET http://localhost:8080/tesla/second
Accept: application/json
Copy the code
Restart the SpringTrapsApplication program and send the HTTP request
You can also annotate @responseStatus on the method
@GetMapping("/third")
@responseStatus (value = httpstatus. NOT_FOUND, reason = "Requested address not found ")
public void response404(a){}Copy the code
Add requests to spring_mvc_traps.http
GET http://localhost:8080/tesla/third
Accept: application/json
Copy the code
@ControllerAdvice or @RestControllerAdvice and @ExceptionHanlder annotations
New advice package, added GlobalExceptionAdvice
@RestControllerAdvice
public class GlobalExceptionAdvice {
@ExceptionHandler(value = CustException.class)
public ResponseEntity<CommonResponse> handleCustException(HttpServletRequest request, CustException ex){
CommonResponse<String> result = new CommonResponse<>(0."");
result.setData(ex.getMessage());
return newResponseEntity<>(result, HttpStatus.BAD_REQUEST); }}Copy the code
Add methods in TeslaController
@RequestMapping("/fourth")
public CommonResponse<String> fourth(a) throws CustException{
throw new CustException("Some error");
}
Copy the code
Restart the application and add requests to spring_mvc_traps.http
###
GET http://localhost:8080/tesla/fourth
Accept: application/json
Copy the code
Click send the request
Pitfalls in time serialization and deserialization
Add an Entity package and add the UserInfo entity class
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
private long id;
private String name;
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date createTime;
}
Copy the code
Define a Controller, UserController; Add GET and POST requests
@RestController
public class UserController {
@GetMapping("/get")
public Map<String, Long> getDateByGet(@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date date){
Map<String, Long> result = new HashMap<>();
result.put("timestamp", date.getTime());
return result;
}
@PostMapping("/post")
public Map<String, String> getDataByPost(@RequestBody UserInfo userInfo){
Map<String, String> result = new HashMap<>();
result.put("id", userInfo.getId().toString());
result.put("name", userInfo.getName());
result.put("createTime", userInfo.getCreateTime().toString());
returnresult; }}Copy the code
Add a spring_mvC_traps_date_transfer. HTTP file in the resource directory to define GET and POST requests
### GET http://localhost:8080/get? date=2022-02-01 23:43:00Accept: application/json
###
POST http://localhost:8080/post
Content-Type: application/json
{
"id": "1",
"name": "stark",
"createTime": "2022-02-01 23:43:00"
}
Copy the code
Send a GET request
Send a POST request
The parameters in the POST request are in the BODY of the request. The attributes of the request parameters do not trigger the @datetimeFormat (pattern=” YYYY-MM-DD HH: MM :ss”) format.
Use JsonFormat annotations
Add an annotation to the createTime attribute in the UserInfo entity class
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
Copy the code
Restart the application and send a POST request
Use a custom format converter @jsondeserialize
@Slf4j
public class DateJacksonConverter extends JsonDeserializer<Date> {
private static final String[] pattern = new String[] {
"yyyy-MM-dd HH:mm:ss"."yyyy/MM/dd"
};
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext context)
throws IOException, JsonProcessingException {
Date targetDate = null;
String originDate = jsonParser.getText();
if (StringUtils.isNotEmpty(originDate)) {
try {
long longDate = Long.parseLong(originDate.trim());
targetDate = new Date(longDate);
} catch (NumberFormatException pe) {
try {
targetDate = DateUtils.parseDate(
originDate, DateJacksonConverter.pattern
);
} catch (ParseException ex) {
log.error("parse error: {}", ex.getMessage());
throw new IOException("parse error"); }}}returntargetDate; }}Copy the code
Modify the UserInfo createTime attributes in the entity class, will be @ JsonFormat annotations annotation, increase @ JsonDeserialize annotations (using = DateJacksonConverter. Class)
Modify the format of createTime in the POST request incoming parameter to initiate the POST request again
POST http://localhost:8080/post
Content-Type: application/json
{
"id": "1",
"name": "stark",
"createTime": "2022/02/01"
}
Copy the code
You can still convert
The partial handling of the time format, which adds the @jsondeserialize annotation to attributes that require time conversion, is less maintainable
Handle Date format conversion globally
Add a global Configuration class for time format handling, add @Configuration and annotate @bean on methods, and hand the class over to the Spring container for management.
@Configuration
public class DateConverterConfig {
@Bean
public DateJacksonConverter dateJacksonConverter(a) {
return new DateJacksonConverter();
}
@Bean
public Jackson2ObjectMapperFactoryBean jackson2ObjectMapperFactoryBean(
@Autowired DateJacksonConverter dateJacksonConverter) {
Jackson2ObjectMapperFactoryBean jackson2ObjectMapperFactoryBean =
new Jackson2ObjectMapperFactoryBean();
jackson2ObjectMapperFactoryBean.setDeserializers(dateJacksonConverter);
returnjackson2ObjectMapperFactoryBean; }}Copy the code
Override the handleType() method in the DateJacksonConverter class to specify deserialization for all Date type attributes
@Override
publicClass<? > handledType() {return Date.class;
}
Copy the code
Comment out the @jsondeserialize annotation on the createTime attribute in the UserInfo entity class, restart the application, and issue the POST request again
Time format conversion can also be achieved.