Spring Boot: Quick Start

Posted by marconi8 on Tue, 17 Sep 2019 03:06:21 +0200

Spring Boot (1): Quick Start

This series of articles is designed to help beginners quickly master the components of Spring Boot using the minimal dependency and simplest configuration to get started.The sample code used in all articles synchronizes the Github and Gitee repositories.

1. What is Spring Boot?

Spring Boot is a new framework provided by the Pivotal team and is designed to simplify the initial build and development of new Spring applications.The framework is configured in a specific way so that developers no longer need to define a template configuration.

The general point is that Spring Boot is not a new framework, it just integrates and implements many of the frameworks by default.

2. What are the benefits?

The big advantage is that it's simple, fast and convenient. Before Spring Boot, what do we need to do if we want to build a framework?

  • Configure web.xml, load Spring and Spring MVC, load various filters, interceptors
  • Configure the database, configuration cache, configuration connection pool, etc. in the configuration file application.xml
  • configure log files
  • Configure reading of various profiles
  • Configure context, configure timer tasks
  • ...
  • Various configurations
  • ...

The author has a project that happened to exist a long time ago, Spring 3.x was still used at that time. I can show you how many configuration files there were for a project at that time:

And if I need to create a new project, a lot of the configuration files are copied in the past and re-debugged, which is inconvenient and time-consuming, and these nightmares are over when Spring Boot comes out.

Advantages of Spring Boot:

  • Getting started faster for all Spring developers
  • Out of the box, provides various default configurations to simplify project configuration
  • Embedded Containers Simplify Web Projects
  • No redundant code generation and XML configuration requirements

3. Quick Start

Targeting: Build a simple RESTful API and implement corresponding unit tests

3.1 How to Build a Project

Spring Boot provides two ways to build projects:

There are currently two more convenient options for creating a springcloud project, the core of which is the same, so you can choose your own convenience for use.

Mode 1:

Open spring's official link:

https://start.spring.io/

Fill in your organization in Group s, typically by writing your company's domain name, such as com.jd or com
baidu, here I'm writing com.springboot directly

Fill in the name of the project in Artifact, where I write spring-boot-quick-start directly.

package chooses jar, java chooses 11 (the latest version of LTS so far), so the basic choices are all selected, and now we're going to start choosing the components of the Spring Boot we're using.

Find the Spring Web in Dependencies and select the Spring Web with the following results:

Finally, click on the green bar button Generate the project below to download, wait until the download is complete, and then decompress the package directly into our editing tool idea.

Mode 2:

Create based on idea, open the idea, first file->new->project, select Spring Initializr, then you can see on the right let's select an initialized service url, the default is the official link above. https://start.spring.io/

Click Next Next, fill in the same information as above about Group, Artifact, java version, package way, etc. to continue Next Next, select dependencies, as in the previous method, find Spring Web in Dependencies, select Spring Web, click next, select project name and storage path, pointClick finish and wait a moment. The first item, spring-boot-quick-start, is fresh ~~

I typically choose the first way to create a Spring Boot project, which does not rely on IDE tools.

3.2 Engineering Structure Analysis

First, let's look at the structure of the project we created, as shown below:

  • pom.xml:maven project configuration file, which configures some basic information about the current project, including the components, versions, etc. that we are currently using.
  • Program entry under src/main/java: Chapter1Application.
  • Configuration file under src/main/resources: application.properties.
  • Test entry under src/test/Chapter1ApplicationTests.

3.3 pom.xml

Here we focus on the <dependencies>tag, which describes the components we introduced

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
  • spring-boot-starter-web:Web module
  • spring-boot-starter-test: Test modules, including JUnit, Hamcrest, Mockito

3.4 Implement a set of RESTful API s for User objects using Spring MVC

The RESTful API is designed as follows:

Request Type URL function
GET / Query User List
POST / Create User
GET /{id} Get user information based on id in url
PUT /{id} Update user information based on id
DELETE /{id} Delete user information based on id

Note: RESTful interfaces should be designed with standard methods and semantics that incorporate security and idempotency considerations, such as GET and HEAD requests, which are secure and do not change the state of the server no matter how many requests are made.GET, HEAD, PUT, and DELETE requests are all idempotent, and the results are always the same no matter how many times the resource is operated on, and subsequent requests will not have more impact than the first one.

Typical uses of GET, DELETE, PUT, and POST are listed below:

GET

  • Safe and idempotent
  • Get Representation
  • Get Representation on Change (Cache)

POST

  • Unsafe and not idempotent
  • Create resources using server-side managed (auto-generated) instance numbers
  • Create subresources
  • Partial Update Resources
  • If it is not modified, the resource is updated (optimistic lock)

PUT

  • Unsafe but idempotent
  • Create a resource with the instance number of client management
  • Update resources by replacement
  • Update resources if not modified (Optimistic lock)

DELETE

  • Unsafe but idempotent
  • Delete resources

The user Model classes are as follows:

public class UserModel {
    private Long id;
    private String name;
    private int age;
    
    // Omit getter s and setter s
}

The REST API implementation classes are as follows:

@RestController
public class UserController {

    // Create a thread-safe Map to use as a data store
    static Map<Long, UserModel> users = new ConcurrentHashMap<>();

    /**
     * Query User List
     * @return
     */
    @GetMapping("/")
    public List<UserModel> getUserList() {
        List<UserModel> list = new ArrayList<UserModel>(users.values());
        return list;
    }

    /**
     * Create User
     * @param userModel
     * @return
     */
    @PostMapping("/")
    public UserModel postUser(@ModelAttribute UserModel userModel) {
        users.put(userModel.getId(), userModel);
        return users.get(userModel.getId());
    }

    /**
     * {id} Get user information based on id in url
     * url The id in can be bound to the parameters of a function through @PathVariable
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public UserModel getUser(@PathVariable Long id) {
        return users.get(id);
    }

    /**
     * Update user information based on id
     * @param id
     * @param userModel
     * @return
     */
    @PutMapping("/{id}")
    public UserModel putUser(@PathVariable Long id, @ModelAttribute UserModel userModel) {
        UserModel u = users.get(id);
        u.setName(userModel.getName());
        u.setAge(userModel.getAge());
        users.put(id, u);
        return users.get(userModel.getId());
    }

    /**
     * Delete user information based on id
     * @param id
     * @return
     */
    @DeleteMapping("/{id}")
    public String deleteUser(@PathVariable Long id) {
        users.remove(id);
        return "success";
    }
}
  • @Controller: Decorates the class to create an object that handles http requests
  • Annotations added after @RestController:Spring4 that originally returned json in @Controller require @ResponseBody to work with. If @RestController is directly used instead of @Controller, the @ResponseBody will no longer need to be configured and json format will be returned by default.

Looking at @RestController, you can see that @RestController itself consists of @ResponseBody and @Controller with the following source code:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {

    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any (or empty String otherwise)
     * @since 4.0.1
     */
    @AliasFor(annotation = Controller.class)
    String value() default "";

}

The unit test classes are as follows:

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootQuickStartApplicationTests {

    private MockMvc mvc;

    @Before
    public void setUp() throws Exception {
        mvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
    }

    @Test
    public void contextLoads() throws Exception {
        RequestBuilder request = null;

        // 1. get checks the list of user s and should be empty
        request = MockMvcRequestBuilders.get("/")
                .contentType(MediaType.APPLICATION_JSON);
        mvc.perform(request)
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();

        // 2. post submits a user
        request = MockMvcRequestBuilders.post("/")
                .param("id", "1")
                .param("name", "Spring Boot")
                .param("age", "18")
                .contentType(MediaType.APPLICATION_JSON);
        mvc.perform(request)
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();


        // 3. get get a list of user s, there should be data just inserted
        request = MockMvcRequestBuilders.get("/")
                .contentType(MediaType.APPLICATION_JSON);
        mvc.perform(request)
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();

        // 4. user whose put modifies id 1
        request = MockMvcRequestBuilders.put("/1")
                .param("name", "Spring Boot Test")
                .contentType(MediaType.APPLICATION_JSON);

        mvc.perform(request)
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();

        // 5. get a user with id 1
        request = MockMvcRequestBuilders.get("/1")
                .contentType(MediaType.APPLICATION_JSON);

        mvc.perform(request)
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();

        // 6. Delete user with id 1
        request = MockMvcRequestBuilders.delete("/1")
                .contentType(MediaType.APPLICATION_JSON);

        mvc.perform(request)
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();

        // 7. get checks the list of user s and should be empty

        request = MockMvcRequestBuilders.get("/")
                .contentType(MediaType.APPLICATION_JSON);

        mvc.perform(request)
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();

    }

}

Launch the test class, and the console prints as follows, capturing only one section for demonstration:

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /
       Parameters = {id=[1], name=[Spring Boot], age=[18]}
          Headers = [Content-Type:"application/json"]
             Body = <no character encoding set>
    Session Attrs = {}

Handler:
             Type = com.springboot.springbootquickstart.controller.UserController
           Method = public com.springboot.springbootquickstart.model.UserModel com.springboot.springbootquickstart.controller.UserController.postUser(com.springboot.springbootquickstart.model.UserModel)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"application/json;charset=UTF-8"]
     Content type = application/json;charset=UTF-8
             Body = {"id":1,"name":"Spring Boot","age":18}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

From console printing, you can see the entire simulation request process as well as the parameters.

Sample Code-Github
Sample Code-Gitee

4. Reference

Spring Boot(1): Introduction
Spring Boot Build RESTful API and Unit Testing

Topics: Java Spring xml SpringBoot JSON