SpringMVC —— 第八章 Spring 与 Web 环境集成
1. 基本三层架构环境的搭建
创建一个 JavaEE 工程,选择模板为 Web 应用程序,并选用 Tomcat 作为服务器
在
pom.xml
中导入需要用到的依赖包的坐标<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.gregperlinli</groupId> <artifactId>spring_mvc</artifactId> <version>1.0-SNAPSHOT</version> <name>spring_mvc</name> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.source>1.8</maven.compiler.source> <junit.version>5.7.1</junit.version> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.8</version> </dependency> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.20</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.8</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.1</version> </plugin> </plugins> </build> </project>
配置 JDBC 和数据源(连接池)
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test jdbc.username=root jdbc.password=root
com.yourname.config.DataSourceConfiguration
import com.mchange.v2.c3p0.ComboPooledDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import javax.sql.DataSource; @PropertySource("classpath:jdbc.properties") public class DataSourceConfiguration { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean("dataSource") public DataSource getDataSource() throws Exception { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass(driver); dataSource.setJdbcUrl(url); dataSource.setUser(username); dataSource.setPassword(password); return dataSource; } }
配置 Spring 容器
com.yourname.config.SpringConfiguration
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @ComponentScan("com.gregperlinli") @Import({DataSourceConfiguration.class}) public class SpringConfiguration { }
编写 Dao 层
com.yourname.dao.UserDao
public interface UserDao { public void save(); }
com.yourname.dao.impl.UserDaoImpl
import com.gregperlinli.dao.UserDao; import org.springframework.stereotype.Repository; @Repository("userDao") public class UserDaoImpl implements UserDao { @Override public void save() { System.out.println("Save running ..."); } }
编写 Service 层
com.yourname.service.UserService
public interface UserService { public void save(); }
com.yourname.service.impl.UserServiceImpl
import com.gregperlinli.dao.UserDao; import com.gregperlinli.service.UserService; import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service("userService") public class UserServiceImpl implements UserService { @Resource(name = "userDao") private UserDao userDao; @Override public void save() { userDao.save(); } }
编写 Web 层
com.yourname.web.UserServlet
import com.gregperlinli.config.SpringConfiguration; import com.gregperlinli.service.UserService; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(name = "UserServlet", value = "/userServlet") public class UserServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class); UserService userService = app.getBean(UserService.class); userService.save(); } }
2. ApplicationContext
应用上下文获取方式
应用上下文对象是通过 new AnnotationConfigApplicationContext
(注解)方式获取的,但是每次从容器中获得 Bean 时都要编写 new AnnotationConfigApplicationContext
(注解),这样的弊端是配置文件加载多次,应用上下文对象创建多次。
在 Web 项目中,可以使用 ServletContextListener
监听 Web 应用的启动,我们可以在 Web 应用启动的时候,就加载 Spring 的配置文件,创建应用上下文对象 **ApplicationContext
**,将其储存到最大的 ServletContext 域中,这样就可以在任意位置获得应用上下文 ApplicationContext
对象了。
示例代码:
com.yourname.listener.ContextLoaderListener
import com.gregperlinli.config.SpringConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener()
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class);
// Store the Spring application context object in the ServletContext domain
ServletContext servletContext = sce.getServletContext();
servletContext.setAttribute("app", app);
System.out.println("Spring container created");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
com.yourname.utils.WebApplicationContextUtils
import org.springframework.context.ApplicationContext;
import javax.servlet.ServletContext;
public class WebApplicationContextUtils {
public static ApplicationContext getWebApplicationContext(ServletContext servletContext) {
return (ApplicationContext) servletContext.getAttribute("app");
}
}
com.yourname.web.userServlet
import com.gregperlinli.service.UserService;
import com.gregperlinli.utils.WebApplicationContextUtils;
import org.springframework.context.ApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "UserServlet", value = "/userServlet")
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
UserService userService = app.getBean(UserService.class);
userService.save();
}
}
3. Spring 提供获取应用上下文的工具
Spring 提供了要一个监听器 ContextLoaderListener
就是对上述功能的封装,该监听器内部加载 Spring 配置文件,创建应用上下文对象,并存储到 ServletContext
域中,提供了一个客户端工具 WebApplicationContextUtils
供使用者获得应用上下文对象。
我们只需要做两件事情
配置
ContextLoaderListener
监听器(需导入 spring-web 坐标)使用
WebApplicationContextUtils
获得应用上下文对象ApplicationContext
示例代码:
pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- Global initialization parameters -->
<context-param>
<param-name>contetConfiguration</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- Configure listeners -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
com.yourname.web.userServlet
import com.gregperlinli.service.UserService;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.context.ApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "UserServlet", value = "/userServlet")
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
UserService userService = app.getBean(UserService.class);
userService.save();
}
}