QA 由浅入深 Spring Framework 5.0(九)- Spring 整合 Java Web

「这是我参与2022首次更文挑战的第38天,活动详情查看:2022首次更文挑战

Spring 整合 JavaWeb 可以实现由Spring来控制事务和管理数据库,Spring容器可以管理Java Bean,有助于降低代码耦合。

一、Spring 整合 Java Web

1.1 工程搭建

在数据库创建porsche表

DROP TABLE IF EXISTS `porsche`;
CREATE TABLE `porsche` (
  `por_id` int(11) NOT NULL AUTO_INCREMENT,
  `por_name` char(100) CHARACTER SET gb2312 COLLATE gb2312_chinese_ci DEFAULT NULL,
  `por_price` double DEFAULT NULL,
  `por_stock` int(11) DEFAULT NULL,
  PRIMARY KEY (`por_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=gb2312;

-- ----------------------------
-- Records of porsche
-- ----------------------------
BEGIN;
INSERT INTO `porsche` VALUES (2, 'Cayenne', 910000, 30);
INSERT INTO `porsche` VALUES (3, 'Macan', 550000, 40);
INSERT INTO `porsche` VALUES (4, 'Taycay 2022', 880000, 50);
INSERT INTO `porsche` VALUES (5, 'Porsche 911', 1270000, 40);
INSERT INTO `porsche` VALUES (6, 'Porsche 718', 540000, 70);
INSERT INTO `porsche` VALUES (7, '918 Spyder', 13380000, 10);
INSERT INTO `porsche` VALUES (8, 'Cayman', 720000, 30);
INSERT INTO `porsche` VALUES (9, 'Boxster', 670000, 110);
INSERT INTO `porsche` VALUES (10, 'Carrera GT', 6450000, 20);
INSERT INTO `porsche` VALUES (11, 'Taycan Tubo S', 880000, 140);
INSERT INTO `porsche` VALUES (12, 'Taycan 2023', 880000, 120);
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;
复制代码

使用IDEA创建maven工程,在pom.xml文件中添加Spring IoC容器依赖、数据库驱动依赖以及其他依赖如jsp等。

<properties>
    <spring-version>5.3.13</spring-version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${spring-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${spring-version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>${spring-version}</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <!--spring jdbc依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${spring-version}</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.16</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.14</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
    <dependency>
        <groupId>javax.servlet.jsp.jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
复制代码

添加 Add Framework Support,选择Web Application

image.png

1.2 增加配置

在resource目录下添加Spring配置文件application.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util-4.3.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.alibaba.com/schema/stat http://www.alibaba.com/schema/stat.xsd http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--包扫描配置-->
    <context:component-scan base-package="com.citi"/>
    <!--引用外部配置文件-->
    <context:property-placeholder location="classpath:database.properties"></context:property-placeholder>

    <!--数据库连接池配置-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driverClassName}"/>
        <property name="url" value="${url}" />
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
        <property name="initialSize" value="${initialSize}"/>
        <property name="maxActive" value="${maxActive}"/>
    </bean>

    <!--配置JDBC Template,注入Spring容器中-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>

    <!--事务管理器配置-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--开启基于注解的配置模式-->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager" />
</beans>
复制代码

在resource目录下增加数据库连接信息的配置database.properties

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/tx?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username=root
password=root
initialSize=5
maxActive=20
复制代码

1.3 测试

新增entity包,增加porsche表对应的实体类Porsche

public class Porsche {

    private Integer porId;
    private String porName;
    private Double porPrice;
    private Integer porStock;
    // 此处省略getter/setter/toString方法
}    
复制代码

新增dao包,增加PorscheDao,在类上增加@Repository注解,由Spring容器管理;并使用Spring JdbcTemplate操作数据库

@Repository
public class PorscheDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public List<Porsche> selectAll(){

        String selectAllSql = "SELECT por_id, por_name, por_price, por_stock FROM porsche";
        RowMapper rowMapper = new BeanPropertyRowMapper<>(Porsche.class);
        List<Porsche> porscheList = jdbcTemplate.query(selectAllSql, rowMapper);
        return porscheList;
    }

}
复制代码

在test包下新增一个测试类PorscheDaoTest,对selectAll方法进行测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:application.xml")
public class PorscheDaoTest {

    @Resource
    private PorscheDao porscheDao;

    @Test
    public void selectAll() {

        List<Porsche> porscheList = porscheDao.selectAll();
        for (Porsche porsche : porscheList) {
            System.out.println(porsche);
        }
    }
}
复制代码

执行测试 image.png 输出porsche表中所有的数据,与预期目标一致。

新增service包,增加PorsheService

@Service
public class PorscheService {

    @Autowired
    private PorscheDao porscheDao;

    public List<Porsche> getPorscheList(){
        return porscheDao.selectAll();
    }
}
复制代码

新增controller包,增加PorscheController,该类调用PorscheService的getPorscheList方法,获取全部数据,并在页面上展示

public class PorscheController extends HttpServlet {
}
复制代码

对于Web项目来说当启动成功后第一次访问时Tomcat容器会创建PorscheController对象,IOC容器创建的对象和Tomcat创建的对象两者无任何关联,Controller对象要交给Tomact来创建,不能增加在类上@Controller注解

PorscheController对象想要获取PorscheService对象就不能通过@Autowired方式来获取,可以通过IOC容器工具来获取,新增util包,实现IOC容器工具ContextUtil

public class ContextUtil {

    public static Object getBean(String beanName){
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
        Object bean = context.getBean(beanName);
        return bean;
    }
}
复制代码

测试这个工具类

public class ContextUtilTest {

    @Test
    public void getBean() {

        Object porscheService = ContextUtil.getBean("porscheService");
        System.out.println(porscheService);
    }
}
复制代码

执行测试

image.png

通过工具类可以获取到PorscheService,从而也就可以调用getPorscheList获得所有数据

public class PorscheController extends HttpServlet {

    private PorscheService porscheService = (PorscheService) ContextUtil.getBean("porscheService");

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 查询所有数据
        List<Porsche> porscheList = porscheService.getPorscheList();
        request.setAttribute("porscheList",porscheList);
        request.getRequestDispatcher("index.jsp").forward(request,response);
        for (Porsche porsche : porscheList) {
            System.out.println(porsche);
        }
        System.out.println("doGet被调用");
    }
}
复制代码

在index.jsp中获取并展示数据

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Index</title>
  </head>
  <body>
    ${requestScope.porscheList}
  </body>
</html>
复制代码

在web.xml中配置PorscheController的访问路径

<servlet>
    <description></description>
    <display-name>PorscheController</display-name>
    <servlet-name>PorscheController</servlet-name>
    <servlet-class>com.citi.controller.PorscheController</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>PorscheController</servlet-name>
    <url-pattern>/porsches</url-pattern>
</servlet-mapping>
复制代码

打开Project Structure,选中Artifacts,将右侧的jar包全部导入左侧WEB-INF目录下的新建的lib文件夹 image.png

配置Tomcat

image.png

启动Tomcat,浏览器输入 http://localhost:8080/porsches

image.png Spring整合Java Web成功

1.4 监听器的作用

在ProscheController中通过IoC容器工具ContextUtil来获取PorscheService,而ContextUtil中是通过下面这行代码来获取一个新的IoC容器。

ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
复制代码

但是这里只有创建容器的代码没有销毁容器的代码,会造成内存被占满的情况。因此希望这个IoC容器能够在合适的时机来创建和销毁,即项目启动时IoC容器创建完成,项目销毁时IoC容器也随之销毁。

Spring Web中的ContextLoaderListener可以监听Tomcat容器,并提供了创建和销毁IoC容器的方法,查看org.springframework.web.context.ContextLoaderListener的源码

image.png 该类提供了容器初始化和销毁的方法

1.4.1 使用监听器

首先需要在pom.xml中增加Spring Web的依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring-version}</version>
</dependency>
复制代码

web.xml中增监听器的配置,同时也需要配置Spring配置文件的路径,监听器通过Spring配置文件中的配置来创建Spring容器

<!--监听器依赖的配置-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:application.xml</param-value>
</context-param>
<!--监听器-->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
复制代码

ContextUtil中就不需要通过new ClassPathXmlApplicationContext("classpath:application.xml")的方式来获取IoC容器了。可以通过ContextLoader.getCurrentWebApplicationContext()来获取;修改ContextUtil的getBean方法的代码

public static Object getBean(String beanName){
    WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
    Object bean = context.getBean(beanName);
    return bean;
}
复制代码

重新启动Tomcat,浏览器再次输入 http://localhost:8080/porsches

image.png 成功输出所有数据

Spring 与 Java Web的集成正式完成,并且得到成功的验证!

猜你喜欢

转载自juejin.im/post/7068998716635480101