Chapter 2 Spring Boot MVC

This chapter is the second chapter of the " Spring Boot Quick Start " series of tutorials. To view all chapters in this series, click here .

content

  • Introduction
  • Source code download
  • Software version
  • Write the Controller class
  • Autoload request parameters
  • Handling return values ​​of complex types
  • Custom return value conversion class HttpMessageConverter
  • Summary note

Introduction

In the previous chapter "Hello Spring Boot", we started with the simplest application and experienced the development process of Spring Boot. In this chapter, we will take you to continue the Spring Boot experience journey and upgrade the Hello Spring Boot program to the Web version. Now the more popular development mode of WEB development is the separation of front and back ends, that is, front-end engineers focus on writing front-end code, and use ajax to call the back-end Http Restful API to obtain data, while back-end engineers focus on implementing Http Restful API. The code engineering and deployment are completely separated, so that as long as the interface is defined, they can develop independently without interfering with each other, and the collaboration efficiency is higher. Therefore, the focus of this article is to describe how to develop Http Restful API services with Spring Boot.

Source code download

The sample code in this chapter is placed on the "Code Cloud", which you can download or browse for free:

https://git.oschina.net/terran4j/springboot/tree/master/springboot-web

Software version

Versions of related software used:

  • Java: 1.8
  • Maven: 3.3.9

The program has been debugged in the above versions and can run normally. Other versions are only for reference.

Write the Controller class

Spring Boot uses Spring MVC as the WEB framework by default. To process HTTP requests, you need to write a Controller class, as shown in the following code:

package com.terran4j.springboot.web;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class HelloController {

	@Autowired
	private HelloService helloService;
	
	@RequestMapping(value = "/hello", method = RequestMethod.GET)
	public void sayHello(HttpServletRequest request, HttpServletResponse response) throws IOException {
		String name = request.getParameter("name");
		String msg = helloService.hello(name);
		response.getWriter().println(msg);
	}
	
}

First, add the @Controller annotation to the class, and then add the @RequestMapping annotation to the method that handles HTTP requests, such as:

@RequestMapping(value = "/hello", method = RequestMethod.GET)

Among them, value is the matching path, and method is the matching method, mainly including GET, POST, PUT, DELETE. The above line means that the GET request with the path /hello will be processed by this method, such as:

http://localhost:8080/hello?name=terran4j

Here, we first use the original HttpServletRequest and HttpServletResponse as input parameters, such as:

sayHello(HttpServletRequest request, HttpServletResponse response)

In some scenarios, it is more flexible to use the HttpServletRequest and HttpServletResponse objects directly, but in most practical scenarios, it is simpler to use the @RequestParamdirect auto-loading parameters (this will be discussed in the following examples).

Then we write a main function and run it:

package com.terran4j.springboot.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class HelloWebApp {

	public static void main(String[] args) {
		SpringApplication.run(HelloWebApp.class, args);
	}

}

After running, we enter the URL in the browser:

http://localhost:8080/hello?name=terran4j

The result of the visit is:

Spring Boot MVC 1.png

Autoload request parameters

In the above example, we read the parameters directly from the HttpServletRequest object, but Spring MVC provides a simpler way, which is to automatically load the request parameters by annotating @RequestParam, as shown in the following code:

	// URL示例:  http://localhost:8080/hello2/param?name=terran4j
	@RequestMapping(value = "/hello2/param", method = RequestMethod.GET)
	@ResponseBody
	public String sayHelloByParam(@RequestParam("name") String name) {
		return helloService.hello(name);
	}

@RequestParam("name") String nameThe meaning of the code is to automatically read the HTTP request parameter whose key is name, and load the value into the method input parameter name. But in this way, if there is no name parameter in the HTTP request, Spring MVC will report an error. The solution is to write it like this, which @RequestParam(value = "name", defaultValue = "")means to set a default value for it. When there is no request parameter, the default value is used, and the default value is an empty string.

This automatic loading method is very intelligent. It will also be automatically parsed according to the type of the parameter object. For example, a count parameter is a number type, which can be directly defined as an Integer or Long type, such as:

sayHello(@RequestParam("count") Integer count, @RequestParam("name") String name)

Spring MVC will automatically resolve to Integer type according to the type of method input parameters, of course, if the corresponding HTTP parameter is not a number, an error will be reported.

In addition, you can also use @PathVariable to load the value in the URL path as a parameter, such as:

	// URL示例:  http://localhost:8080/hello2/path/terran4j
	@RequestMapping(value = "/hello2/path/{name}", method = RequestMethod.GET)
	@ResponseBody
	public String sayHelloByPath(@PathVariable("name") String name) {
		return helloService.hello(name);
	}

It automatically takes the section after /hello2/path/ from the URL path as the value of the name parameter. If readers are familiar with Restful-style APIs, they know that this approach is very suitable for Restful APIs.

Note that the @ResponseBody annotation must not be missing on the method, which means that the return result of the method is directly written into the HTTP Response Body. As for what is written, it is determined by HttpMessageConverter. The default HttpMessageConverter in Spring MVC is a json string that automatically converts the returned object, which will be discussed in the next section.

Handling return values ​​of complex types

So far, our return value is just a simple String type. What if it is a complex java bean defined by ourselves? We first define a java bean class named HelloBean, the code is as follows:

package com.terran4j.springboot.web;

import java.util.Date;

public class HelloBean {
	
	private String name;
	
	private String message;
	
	private Date time;

	public final String getName() {
		return name;
	}

	public final void setName(String name) {
		this.name = name;
	}

	public final String getMessage() {
		return message;
	}

	public final void setMessage(String message) {
		this.message = message;
	}

	public final Date getTime() {
		return time;
	}

	public final void setTime(Date time) {
		this.time = time;
	}

	@Override
	public String toString() {
		return "Hello [name=" + name + ", message=" + message + ", time=" + time + "]";
	}
	
}

This bean has two attributes of type name and msg of type String, as well as attributes of type time, of type Date, and their getter and setter methods.

Then we transform the previous Controller class into this:

package com.terran4j.springboot.web;

import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController3 {
	
	private static final Logger log = LoggerFactory.getLogger(HelloController3.class);

	@Autowired
	private HelloService helloService;
	
	// URL示例:  http://localhost:8080/hello3?name=terran4j
	@RequestMapping(value = "/hello3", method = RequestMethod.GET)
	public HelloBean sayHello(@RequestParam("name") String name) {
		HelloBean hello = new HelloBean();
		hello.setName(name);
		hello.setMessage(helloService.hello(name));
		hello.setTime(new Date());
		if (log.isInfoEnabled()) {
			log.info("hello bean is: {}", hello);
		}
		return hello;
	}
	
}

Note: In the above code, the annotation on the class is changed from @Controller to @RestController, and the annotation on the method is missing @ResponseBody. In fact, @RestController = @Controller + @ResponseBody, which means that with @RestController, each method (with @RequestMapping) is automatically annotated with @ResponseBody.

In the above code, the method returns a HelloBean object, we run the main program, and then access the URL:

http://localhost:8080/hello3?name=terran4j

The result is as follows:

Spring Boot MVC 3.1

You can see that Spring MVC automatically converts the java bean object into a json string and returns it.

But there is still a problem, the attribute is Date timedisplayed in the timestamp format of long type, not in a format that is easy for humans to understand (such as "2017-03-09 18:42:00"), and the json string is compressed into one line It's very ugly. Usually, the official project returns a lot of data. If it is crowded like this, it will be difficult to debug the program.

Is there any way to optimize the returned json string result? The answer is obviously yes. In the next section, we will explain how to convert the return value into the json string format we want by injecting a custom HttpMessageConverter.

Custom return value conversion class HttpMessageConverter

Spring MVC uses the HttpMessageConverter class to convert the return value into the final result and write it into the Http Response Body after calling the Controller method. We can define an HttpMessageConverter object to replace the HttpMessageConverter object provided by Spring MVC by default.

As shown in the following code:

package com.terran4j.springboot.web;

import java.text.SimpleDateFormat;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;

@EnableWebMvc
public class HelloWebMvcConfigurer extends WebMvcConfigurerAdapter {
	
	private static final Logger log = LoggerFactory.getLogger(HelloWebMvcConfigurer.class);

	public static final ObjectMapper createObjectMapper() {
		ObjectMapper objectMapper = new ObjectMapper();

		objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);

		// 属性为空时(包括 null, 空串,空集合,空对象),不参与序列化。
		objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);

		// Date 对象在序列化时,格式为 yyyy年MM月dd日 HH时mm分ss秒 。
		objectMapper.setDateFormat(new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒"));

		objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
		objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
		objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
		objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);

		// json串以良好的格式输出。
		objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);

		// 当属性为空或有问题时不参与序列化。
		objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

		// 未知的属性不参与反序列化。
		objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		
		if (log.isInfoEnabled()) {
			log.info("create objectMapper done.");
		}
		return objectMapper;
	}

	@Override
	public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
		ObjectMapper objectMapper = createObjectMapper();
		MappingJackson2HttpMessageConverter convertor = new MappingJackson2HttpMessageConverter(objectMapper);
		converters.add(0, convertor);
	}

}

First, we createObjectMapper()create an ObjectMapper object by ourselves. ObjectMapper is a high-performance json processing tool provided by the open source project Jackson. It provides the ability to convert json and java objects to each other, and has very strong configurability, such as the following line of code :

        // Date 对象在序列化时,格式为 yyyy年MM月dd日 HH时mm分ss秒 。
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒"));

It means that you can convert objects of type Date into the date format you want. Of course, ObjectMapper has a lot of configuration items, so I won't go into details. Interested friends can find relevant information online.

Then we inject the custom HttpMessageConverter into Spring MVC, as shown in the following code:

	@Override
	public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
		ObjectMapper objectMapper = createObjectMapper();
		MappingJackson2HttpMessageConverter convertor = new MappingJackson2HttpMessageConverter(objectMapper);
		converters.add(0, convertor);
	}

There may be many HttpMessageConverter objects in Spring MVC, and the runtime traverses from the converters list until an HttpMessageConverter object is found that can handle the current HTTP request. We need to add our own HttpMessageConverter object to the first place in the converters list, in order to get the highest priority, such as code: converters.add(0, convertor);We use the ready-made MappingJackson2HttpMessageConverter class provided by the jackson project (it implements the HttpMessageConverter interface), we only need to create our own The ObjectMapper object can be passed in.

Finally, we introduce this class in the main program with the @Import annotation, the code is as follows:

package com.terran4j.springboot.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;

@Import(HelloWebMvcConfigurer.class)
@SpringBootApplication
public class HelloWebApp {

	public static void main(String[] args) {
		SpringApplication.run(HelloWebApp.class, args);
	}

}

The @Import(HelloWebMvcConfigurer.class)above introduces the HelloWebMvcConfigurer class we defined into the main program.

Finally, we run the main program and enter the URL in the browser:

http://localhost:8080/hello3?name=terran4j

The result is as follows:

The result after introducing HelloWebMvcConfigurer

Compared with the previous json string result, the format is more elegant, and the display format of Date is also easier to read:Results before introducing HelloWebMvcConfigurer

Summary note

This chapter is the second chapter of the " Spring Boot Quick Start " series. In this chapter, we explain how to use Spring Boot to develop Http Restful services. In the next chapter, we will explain how to access the database in Spring Boot. Welcome to the next chapter "Spring Boot". Boot JPA.

Click here to view all chapters in this series. (The goal of this series is to help programmers with Java development experience to quickly master the basic skills of using Spring Boot to develop, and feel the minimalist development style and super cool programming experience of Spring Boot.)

In addition, we have a WeChat public account called SpringBoot and Microservices . Interested students, please scan the QR code below and follow it. After following, you can receive the technical dry goods we share regularly!SpringBoot and Microservices - Official Account QR Code

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325477124&siteId=291194637