We have introduced some common knowledge points of Spring MVC(1), but there are still some missing points, such as putting the request into Session, it is too boring to configure in the configuration file, can we move the configuration file to the configuration class, SSM(Spring Spring MVC MyBatis) integration.

To convert configuration files into configuration classes, you need to understand some of Spring’s core annotations, such as @import. This annotation has been introduced in the welcome to Spring age (1) column.

In the session

How do we put data into sessions? In the days of native servlets, we would simply get the HttpSession object from HttpServletRequest, as follows:And of course you can use that in the Spring MVC framework, Spring MVC also provides @sessionAttributes for putting data into a Session, @sessionAttribute for putting values in a Session, and by looking through the source code, We found that @sessionAttributes can only apply to classes. When browsing the source code, we found the @sessionAttribute annotation. We thought it was the same as @sessionAttributes. This is used to fetch Session values and put them into method parameters, only method parameters.SessionAttributes = ‘value’ and ‘name’; SessionAttributes = ‘value’; Then that data will be put into the Session as well. The Type attribute is put into Session as long as the data in the request domain is of that Type. Let’s now test @sessionAttributes:

Controller
SessionAttributes(value = "password")
public class SessionDemoController {

    @RequestMapping(value = "/session", method = RequestMethod.GET)
    public String testGet(@RequestParam(value = "name") String userName, @RequestParam(value = "password") String password ,Model model) {
        System.out.println("username:" + userName);
        System.out.println("password:" + password);
        model.addAttribute("password",password);
        return "success"; }}Copy the code

success.jsp:

<%@ page contentType="text/html; charset=UTF-8" language="java" %><html>
<head>
    <title>Title</title>
</head>
<body>
<h1> success </h1>
<h1> username:  ${sessionScope.userName}</h1>
<h1> password: ${sessionScope.password}</h1>
</body>
</html>
Copy the code

url: http://localhost:8080/studySpringFrameWork_war_exploded/session? name=aa&&password=aaa

Test results:SessionAttribute:

RequestMapping(value = "/servlet", method = RequestMethod.GET)
    public String testGet(@RequestParam(value = "name") String userName,  @SessionAttribute(value = "password")String password) {
        System.out.println("username:" + userName);
        System.out.println("password:" + password);
        return "success";
    }
Copy the code

url: http://localhost:8080/studySpringFrameWork_war_exploded/servlet?name=aaaTest results:You can see there’s no password in the URL, but the password still prints out with a value, and that’s the value in the session.

The configuration of the profile is moved to the configuration class

Simply put, the essence of a configuration file is to register objects of the corresponding class into the IOC container according to the label when reading the configuration file. However, too many configuration files are also very annoying, can be converted to the form of configuration classes? Spring MVC: Sure. Var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var var By org. Springframework. Web. Servlet. Support. AbstractAnnotationConfigDispatcherServletInitializer to transplant, the above comments is very clear, sometimes run into English don’t resist, Read and accumulate a few more words, most grammar is not difficult:If you don’t like this format, you can go to the corresponding Java Doc. Here is the address:

  • Docs. Spring. IO/spring – fram…

Then we see WebApplicationInitializer annotation:

Interface to be implemented in Servlet 3.0+ Environments in order to configure the ServletContext – as opposed to (or possibly in conjunction with) the traditional web.xml-based approach. This interface was implemented in Servlet 3.0 and later to enable the configuration of ServletContext as a configuration class, as opposed to the traditional web.xml based configuration approach.

Implementations of this SPI will be detected automatically by SpringServletContainerInitializer, which itself is bootstrapped automatically by any Servlet 3.0 container. See its Javadoc for details on this bootstrapping mechanism.

SpringServletContainerInitializer will automatically monitor the interface implementation class, and supported by any Servlet version 3.0 or more container load automatically.

The Spring MVC configuration class can only be used in servlets that support Servlet 3.0. The following comment states that the interface implementation class is automatically loaded by the Servlet container. But this is not we choose to implement WebApplicationInitializer, do some trouble, the Spring MVC provides a simple Web initializer: Org. Springframework. Web. Servlet. Support. AbstractAnnotationConfigDispatcherServletInitializer, for our use. AbstractAnnotationConfigDispatcherServletInitializer is an abstract class, we inherit it, and then to inherit it see:

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protectedClass<? >[] getRootConfigClasses() {return new Class[0];
    }

    @Override
    protectedClass<? >[] getServletConfigClasses() {return new Class[0];
    }	
    /** * set the intercepting URL *@return* /
    @Override
    protected String[] getServletMappings() {
        return new String[0]; }}Copy the code

GetRootConfigClasses and getServletConfigClasses are two methods that load configuration classes. The official documentation provides the Java Config and XML-based equivalents:Let’s take a look at the comparison:GetServletConfigClasses is the same as loading the Spring MVC configuration file. GetServletConfigClasses is the URL to be intercepted. GetRootConfigClasses. Spring MVC allows us to register multiple dispacherservlets, which can be separated from other Spring MVC configuration files. What if there are some beans that need to be shared between these different Dispatcherservlets? GetRootConfigClasses loads the top-level configuration classes that are shared by the dispatcherservlets.

Currently we only have one DispatcherServlet, so we’ll just create an empty class. So AppInitializer was reconfigured to look something like this:

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
	
    @Override
    protectedClass<? >[] getRootConfigClasses() {return new Class[]{RootConfig.class};
    }

    @Override
    protectedClass<? >[] getServletConfigClasses() {return new Class[]{WebConfig.class};
    }

    /** * used to set the intercepting URL **@return* /
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"}; }}@Configuration
public class RootConfig {}@EnableWebMvc
@ComponentScan(basePackages = {"org.example.mvc"})
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(newMyHandlerInterceptor()); }}Copy the code

@enableWebMVC is new and we need to cover it briefly here.

@ EnableWebMvc profile

We could write another article about @enableWebMVC, because Spring does a lot of work on this annotation. It’s not an easy thing to do. I’m just going to give you an idea of what @enableWebMVC does in a configuration file.

Can turn the official document, try to turn the official document, the official document has this part of the introduction:This screenshot seems not very clear, let’s take a look at it in the IDE:

< MVC :annotation-driven/> there's a lot of videos that say, well, this is turning a class with @Controller in it into a class that handles requests, but I don't know if it's related to the Spring MVC version THAT I'm using, but I can do without it.Copy the code

But suggest you still add, explain clearly don’t add also line (may give some inexplicable problems), but this is not a simple thing, because it involves a lot of source interpretation, if interested in understanding can see:

  • The spring MVC<mvc:annotation-driven/>What’s the use?

Interceptor and other tags porting

This class inherits from WebMvcConfigurer. In it, I’ve overridden the addInterceptors method. As you can infer from the name, this method adds an interceptor. Then we will write it in its entirety:

@EnableWebMvc
@ComponentScan(basePackages = {"org.example.mvc"})
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyHandlerInterceptor()).addPathPatterns("/ * *").excludePathPatterns("login"); }}Copy the code

Let’s compare:

About bean tags we do not talk about how to transplant, this in welcome to the Spring era (a) on the IOC column has talked about, here will not talk again. The WebMvcConfigurer method here does not take out the details, you can see the note. We’re just going to cover the general idea here.

Test the

Note that you need to comment out the configuration that web.xml preloads. Basically, the test was successful. I’m not going to post any code here. I put the code on the code cloud, so if you’re interested, you can look it up. Basically, this is the end of Spring MVC. The address is as follows:

  • github.com/CXK6013/SSM

Integration of SSM

Introduction to SSM integration

Here we can start to talk about SSM integration. At that time, when I learned SSM integration with my classmates, some students did not understand the idea, so they just memorized it. Sometimes they tried to do integration by themselves, but if they memorized wrong, the integration failed. Here I want to talk about the idea, and with this idea, when I want to do integration again, I’ll know where I went wrong. As I look at this, I hope you have some idea of Spring’s thinking, and I recommend reading my Spring series:

  • Welcome to the Spring era – Introduction
  • Welcome to the Spring era
  • Proxy pattern – Introduction to AOP
  • Welcome to the Spring era (ii) AOP

Note here is the SSM integration, then MyBatis also required, if not please refer to my MyBatis series of articles.

  • Pretend to be a white man

If you don’t know Spring MVC, please refer to my Spring MVC series:

  • Pretend to be white and learn Spring MVC

SSM integration idea – Spring rules the world

Spring Framework is a successful Framework to solve the problem of complex dependencies between objects, in the case of hard coding, elegant and configurable objects, then other frameworks should also be incorporated into the Spring Framework, let’s take the Framework’s objects elegant. This is a consolidation of ideas, putting the core objects of the framework into an IOC container and taking them out. Once again, assuming that MyBatis needs data source and scan XML, we will configure it in the IOC container. Then use the method provided by Spring to fetch objects. The core idea of SSM integration is to put Spring MVC, MyBatis core object into IOC container, and then we take.

So what is our vision for MyBatis integration? Let’s look at the MyBatis code:How to integrate MyBatis into Spring to achieve this effect? Just looking at the current code, we put the SqlSessionFactory into the IOC container, get the session from the IOC container, and call the getMapper method. Is that a bit of a hassle? Is there a simpler solution? This solution is called Mybatis – Spring and depends on the following:

  <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
 </dependency>
Copy the code

The solution is to put Mapper interfaces (Xml corresponding interfaces, hereinafter referred to as Mapper objects) into the IOC container, which we can only inject with the @AutoWired annotation where the corresponding Mapper is needed

Integration of MyBatis

We are only going to cover xmL-based, configuration class-based, and simply move the bean label to the configuration class.

Based on XML

The Druid connection pool is used to manage data sources.

<! Mydb = "placeholderConfigurer" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:jdbc.properties</value> </list> </property> </bean>Copy the code
   <bean id = "dataSource" class = "com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.dev.driver}">
        </property>
        <property name = "url" value="${jdbc.dev.driver}">
        </property>
        <property name = "username" value = "${jdbc.dev.username}">
        </property>
        <property name = "password" value = "${jdbc.dev.password}">
        </property>
    </bean>
Copy the code

To implement putting Mapper interface objects into IOC containers, there are two core classes:

  • org.mybatis.spring.SqlSessionFactoryBean
  • org.mybatis.spring.mapper.MapperScannerConfigurer

SqlSessionFactoryBean overview:MapperScannerConfigurer overview:

In fact, there is an official document:The address is:Mybatis.org/spring/zh/g…The origin of Mybatis – Spring and how to integrate it are described above.

  <bean  id = "sqlSessionFactory"  class = "org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref = "dataSource"></property>
        <property name = "mapperLocations" value="org\example\mybatis\*.xml">
        </property>
    </bean>

    <bean  id = "mapperScannerConfigurer" class = "org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value = "org.example.mybatis" />
        <property name="sqlSessionFactoryBeanName" value = "sqlSessionFactory"></property>
     </bean> 
Copy the code

Some students may ask, what about the previous configuration file? How to switch the environment? The SqlSessionFactoryBean has a Configuration field of type Configuration. Let’s look at the Configuration class:And then you configure it. If you don’t want to configure the bean, you can also specify the path. You can specify the configuration file location of MyBatis via configLocation of SqlSessionFactoryBean.

Integration of Spring MVC

In fact, I was already using Spring when I introduced Spring MVC above, and you probably didn’t feel the integration process, which is called seamless integration. Next, if you have multiple Dispatcherservlets but a batch of beans is shared, you don’t want to configure one in each configuration file. What to do. In the case of the configuration class, we configured it through getRootConfigClasses. Remember how it was written in XML?

<web-app>
	
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
	<! -- this is used to load beans shared by DispatcherServlet -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/root-context.xml</param-value>
    </context-param>
    <servlet>
        <servlet-name>app1</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/app1-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>app1</servlet-name>
        <url-pattern>/app1/*</url-pattern>
    </servlet-mapping>

</web-app>
Copy the code

episode

I thought the integration was going well, so I decided to wrap it up. Then I started the project. Then I reported the jar package shortage.

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.2.8. RELEASE</version>
    </dependency>
    <! -- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.8. RELEASE</version>
    </dependency>
Copy the code

Then I found that after making up, I still failed to inject. At this time, I fell into deep thought. The biggest pain is still that I do not know where I am wrong. Because the console doesn’t give an error, and what’s worse, the program doesn’t give an error. So I started to check, loading the configuration file in the main function to try:

public static void main(String[] args) throws IOException {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-MVC.xml");
    BlogMapper blogMapper = applicationContext.getBean(BlogMapper.class);
    System.out.println(blogMapper.selectAllReturnMap());
}
Copy the code

I suspect that my configuration file has not been loaded. Here is my configuration in web.xml:Then there is the Spring MVC configuration file:I assume that the configuration file in the context-param tag is loaded first, and that the individual beans are initialized in the process. Then load the Spring MVC configuration file and initialize some Spring MVC beans. I then moved the code integrating MyBatis into ApplicationContext.xml and there it is.

Row of wrong ideas

Basically, I deduced that my Spring-MVC configuration file had not loaded successfully after importing logging, which prints beans created by the Spring IOC container:When I load the Spring MVC configuration file in the main function alone, I see a successful sqlSessionFactory creation log, but not when I start Tomcat. That’s why I wonder if the spring-MVC configuration file loaded a little late. And then verify that it is. For example, Log 4j2 does not support the properties configuration file and must be named log4j2.properties. Then how to configure the log, follow the GitHub configuration. The corresponding project address on GitHub is as follows:

  • github.com/CXK6013/SSM

Source code selection of Spring MVC implementation process

Next, we will look at the Spring MVC implementation process, which is also a frequent interview question, to further our understanding of Spring MVC. The DispatcherServlet source code is too large to show, so let’s look at the two core methods:

  • HandlerExecutionChain
  • DoDispatch (Request distribution)

We’ll focus on the doDispath method: Based on this, we can roughly draw the Spring MVC execution flow:In fact, the Spring MVC implementation process is well known, after all, it is a frequent interview question, but I want to look at it from the source point of view. Basically the whole process is in the Dispatch method of DispatcherServlet, if you are interested, you can also take a look.

To summarize

Each time to learn the framework will have a new cognition, this is also a small receipt of goods, the heart of the previous questions are cleared. I hope it will be helpful for you to learn Spring MVC, but is that the end? Far from it. Don’t you find these configurations a little annoying? There is also dependency management, in fact, WHEN I do it is very careful, for fear of dependency conflict, can you simplify it? Of course, the answer will be given by Spring Boot, a star member of the Spring family.

The resources

  • Rounding out the @ EnableWebMvc
  • How to configure Spring MVC using pure Java Config
  • Spring MVC official documentation
  • Differences between getServletConfigClasses() and getRootConfigClasses()