SpringMVC02- View resolver and controller

Environmental description

  • JDK 17
  • SpringMVC 6.0.6
  • Tomcat 10.0.12
  • Thymeleaf 3.1.2.RELEASE

Environment preparation

Add SpringMVC dependency and Thymeleaf dependency:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>6.0.6</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring6</artifactId>
    <version>3.1.2.RELEASE</version>
</dependency>

Configuring view resolvers and controllers

Configure the view resolver and register the corresponding ViewResolver as a Bean (Thymeleaf template view resolver configuration steps: template resolver -> template engine -> view resolver):

@EnableWebMvc
@ComponentScan("com.example.controller")
@Configuration
public class WebConfig {<!-- -->

    //Configure template parser Bean
    @Bean
    public SpringResourceTemplateResolver templateResolver(){<!-- -->
        SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
        //The location where the HTML page files that need to be parsed are stored. The default is the webapp directory. If it is under the classpath, you need to add the classpath: prefix.
        resolver.setPrefix("/");
        resolver.setSuffix(".html"); //The suffix name that needs to be resolved
        resolver.setCharacterEncoding("UTF-8");
        return resolver;
    }

    //Configure template engine Bean
    @Bean
    public SpringTemplateEngine springTemplateEngine(ITemplateResolver resolver){<!-- -->
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(resolver);
        return engine;
    }

    // Use ThymeleafViewResolver as the view parser to parse HTML pages
    @Bean
    public ThymeleafViewResolver thymeleafViewResolver(SpringTemplateEngine engine){<!-- -->
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setOrder(1);
        resolver.setCharacterEncoding("UTF-8");
        resolver.setTemplateEngine(engine);
        return resolver;
    }
}

Create a Controller and write a method to handle requests for the corresponding address:

@Controller
public class HelloController {<!-- -->
    @RequestMapping("/index")
    public ModelAndView index(){<!-- -->
        // Return the ModelAndView object. After returning, it will be processed by the view parser. Fill in the view name here.
        return new ModelAndView("index");
    }
}

Then create an html file under the classpath root (webapp):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Test</title>
</head>
<body>
    <p>Welcome to GayHub, the world's largest same-sex dating website</p>
</body>
</html>

Launch to access the front-end interface.

In the Controller we can also provide data directly to the Model model layer:

@RequestMapping("/index")
public ModelAndView index(){<!-- -->
    ModelAndView modelAndView = new ModelAndView("index");
    modelAndView.getModel().put("key", "33525Me and you");
    return modelAndView;
}

Thymeleaf can receive the passed data for parsing:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Test</title>
</head>
<body>
<p>Welcome to GayHub, the world's largest same-sex dating website</p>
<div th:text="${key}"></div>
</body>
</html>

In addition, for convenience, you can directly return the View name in the Controller, and SpringMVC will automatically package it into a ModelAndView object (make sure there is a horizontal line under the view name and hold down Ctrl to jump, the configuration is correct):

@RequestMapping("/index")
public String index(){<!-- -->
    return "index";
}

You can also add a Model separately as a formal parameter for setting. SpringMVC will automatically help us pass the instance object through dependency injection:

@RequestMapping("/index")
public String index(Model model){<!-- -->
    model.addAttribute("key", "Me and you");
    return "index";
}

Finally, since our page may have some static resources such as css, js, etc., we need to configure it here so that the static resources can be parsed through the default Servlet provided by Tomcat. We need to let the configuration class implement WebMvcConfigurer interface, so that when the web application starts, further configuration will be performed based on the content in our overridden method:

@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {<!-- -->
    configurer.enable(); //Enable the default Servlet
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {<!-- -->
    // Match the resourceHandler and map the URL to location
    // Configure the access path of static resources and release static resources
    registry.addResourceHandler("/static/**")
            .addResourceLocations("/static/");
}

Modify html file:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Test</title>
    <!-- To reference static resources, Thymeleaf's URL link expression is used here. Thymeleaf will automatically add the name of the web application to the front of the link -->
    <script th:src="@{/static/test.js}"></script>
</head>
<body>
<p>Welcome to GayHub, the world's largest same-sex dating website</p>
<div th:text="${key}"></div>
</body>
</html>

Create test.js file:

window.alert("Welcome to GayHub, the world's largest same-sex dating website")

Start the server and access the page. A pop-up window will be displayed when the page loads.

Related notes

@RequestMapping annotation

//Handle multiple requests
@RequestMapping({<!-- -->"/index", "/test"})

// wildcard
?: Indicates any character. For example, @RequestMapping("/index/x?") can match /index/xa, /index/xb, etc.
*: Indicates any 0-n characters. For example, @RequestMapping("/index/*") can match /index/lbwnb, /index/yyds, etc.
**: Indicates the current directory or a multi-level directory based on the current directory. For example, @RequestMapping("/index/**") can match /index, /index/xxx, etc.

//Limit the request method
@RequestMapping(value = "/index", method = RequestMethod.POST)
Derived annotations: @PostMapping, @GetMapping, etc.

// Use the params attribute to specify which request parameters the request must or cannot carry, or you can set the value directly
@RequestMapping(value = "/index", params = {<!-- -->"username", "!password"})

// The header attribute usage is consistent with params, but it requires what content needs or cannot be carried in the request header.
@RequestMapping(value = "/index", headers = "!Connection")

Detailed explanation of @RequestParam and @RequestHeader

// Get the parameters in the request: add a formal parameter to the method, and add the @RequestParam annotation in front of the formal parameter
// If the parameter name is the same as the formal parameter name, the parameter value can be obtained even without adding @RequestParam
// Once @RequestParam is added, the request must carry the specified parameters,
// You can also set the require attribute to false to make the attribute non-required, or set a default value for the parameter
@RequestMapping(value = "/index")
public ModelAndView index(@RequestParam("username") String username){<!-- -->

// If you need to use some of the original Servlet classes, just add HttpServletRequest or HttpServletResponse as formal parameters.
@RequestMapping(value = "/index")
public ModelAndView index(HttpServletRequest request){<!-- -->

// You can also directly pass the request parameters to an entity class. All parameters must be included in the set method or constructor method. The request parameters will be automatically matched according to the field names in the class.
@RequestMapping(value = "/index")
public ModelAndView index(User user){<!-- -->

@CookieValue and @SessionAttrbutie

By using the @CookieValue annotation, we can also quickly obtain the cookie information carried in the request. The same goes for @SessionAttrbutie:

@RequestMapping(value = "/index")
public ModelAndView index(HttpServletResponse response,
                          @CookieValue(value = "test", required = false) String test){<!-- -->
    System.out.println("The cookie value obtained is:" + test);
    response.addCookie(new Cookie("champion", "theshy"));
    return new ModelAndView("index");
}
@RequestMapping(value = "/index")
public ModelAndView index(@SessionAttribute(value = "test", required = false) String test,
                          HttpSession session){<!-- -->
    session.setAttribute("champion", "theshy");
    System.out.println(test);
    return new ModelAndView("index");
}

Redirect and request forwarding

//Just add a prefix in front of the view name
@RequestMapping("/index")
public String index(){<!-- -->
    return "redirect:home";
}

@RequestMapping("/hello")
public String index(){<!-- -->
    return "forward:home";
}

@RequestMapping("/home")
public String home(){<!-- -->
    return "home";
}

Bean scope

Spring involves the single instance and multiple instance modes of Bean. Spring MVC further divides the scope of Bean:

  • request: Each HTTP request using the bean defined in the request scope will generate a new instance, and the bean will disappear after the request is completed.
  • Session: For each session, a Bean defined using session scope will generate a new instance, and the Bean will disappear after the session expires.
  • global session: Not commonly used.
@Bean
@RequestScope // @SessionScope Same reason
public TestBean testBean(){<!-- -->
    return new TestBean();
}
@Controller
public class MainController {<!-- -->

    @Resource
    TestBean bean;

    @RequestMapping(value = "/index")
    public ModelAndView index(){<!-- -->
        System.out.println(bean);
        return new ModelAndView("index");
    }
}

Restful style

The Restful style design allows parameters to be passed to the server through URL splicing. The purpose is to make the URL look more concise and practical, and can make full use of multiple HTTP request methods (POST/GET/PUT/DELETE) to execute the same request address. Different types of operations. That is, we can get the parameters directly from the request path:

http://localhost:8080/mvc/index/123456
@RequestMapping("/index/{str}")
public String index(@PathVariable String str) {<!-- -->
    System.out.println(str);
    ...