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.