Spring框架学习

文章40 |   阅读 14374 |   点赞0

来源:https://blog.csdn.net/yerenyuan_pku/category_6457009.html

Spring入门第四讲——使用Spring的IoC完成CRM系统中保存客户的操作

x33g5p2x  于2021-12-18 转载在 其他  
字(8.9k)|赞(0)|评价(0)|浏览(389)

需求概述

还记得我们在学习Struts2框架时提及的CRM系统吗?CRM系统中有一个客户信息管理模块,该模块包括的功能有:

  • 新增客户信息
  • 客户信息查询
  • 修改客户信息
  • 删除客户信息

而在本讲中,咱主要实现的是新增客户的功能。

环境搭建

创建web项目,引入jar包

创建一个web项目,例如spring4_crm,并引入相关的jar包,那引入哪些jar包呢?由于我们在web层使用的Struts2框架,所以得导入与Struts2框架开发相关的依赖jar包。

我们还需要使用Spring框架对Bean进行管理,所以,还得导入Spring开发的基本的jar包。

温馨提示:我在本讲中说是使用Spring的IoC完成CRM系统中保存客户的操作,但压根就是一伪操作,因为我并不打算在dao层引入Hibernate框架,那当然就不会真正将客户信息保存到数据库中了。其实,本讲关注的点是Spring如何整合web项目。

引入相关的配置文件

首先,在项目中引入Struts2的核心配置文件(struts.xml),它里面的内容一开始是空的哟!然后在项目的web.xml文件中配置Struts2的核心过滤器。

接着,在项目中引入Spring的配置文件,即applicationContext.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" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	       
</beans>

最后,在项目中引入日志记录文件(log4j.properties),其内容如下:

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c\:mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###
# error warn info debug trace
log4j.rootLogger= info, stdout

创建数据库和表

创建一个数据库,并在该数据库下新建一张客户表,这里笔者使用的数据库是MySQL。

create database spring_crm;
use spring_crm;

CREATE TABLE `cst_customer` (
	`cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
	`cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
	`cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
	`cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
	`cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
	`cust_phone` varchar(64) DEFAULT NULL COMMENT '固定电话',
	`cust_mobile` varchar(16) DEFAULT NULL COMMENT '移动电话',
	PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

创建包结构

引入相应的页面

CRM系统中用到的所有页面可以点击我给的百度网盘链接行下载。

这里,除了要将CRM系统中用到的所有页面导入到我们的项目之外,还记得将所有的htm静态页面改为jsp页面。咋改?不用我教吧!改完之后,发布我们的项目,试着访问一下项目的首页,看能不能出现下面的效果。

至此,开发环境就搭建起来了,接下来就是编写代码实现需求的事情了。

案例代码实现

编写Customer实体类

在com.meimeixia.domain包下创建一个Customer实体类。

package com.meimeixia.domain;

public class Customer {

	private Long cust_id;
	private String cust_name;
	private String cust_source;
	private String cust_industry;
	private String cust_level;
	private String cust_phone;
	private String cust_mobile;
	
	
	public Long getCust_id() {
		return cust_id;
	}
	public void setCust_id(Long cust_id) {
		this.cust_id = cust_id;
	}
	public String getCust_name() {
		return cust_name;
	}
	public void setCust_name(String cust_name) {
		this.cust_name = cust_name;
	}
	public String getCust_source() {
		return cust_source;
	}
	public void setCust_source(String cust_source) {
		this.cust_source = cust_source;
	}
	public String getCust_industry() {
		return cust_industry;
	}
	public void setCust_industry(String cust_industry) {
		this.cust_industry = cust_industry;
	}
	public String getCust_level() {
		return cust_level;
	}
	public void setCust_level(String cust_level) {
		this.cust_level = cust_level;
	}
	public String getCust_phone() {
		return cust_phone;
	}
	public void setCust_phone(String cust_phone) {
		this.cust_phone = cust_phone;
	}
	public String getCust_mobile() {
		return cust_mobile;
	}
	public void setCust_mobile(String cust_mobile) {
		this.cust_mobile = cust_mobile;
	}
	@Override
	public String toString() {
		return "Customer [cust_id=" + cust_id + ", cust_name=" + cust_name + ", cust_source=" + cust_source
				+ ", cust_industry=" + cust_industry + ", cust_level=" + cust_level + ", cust_phone=" + cust_phone
				+ ", cust_mobile=" + cust_mobile + "]";
	}
	
}

在菜单页面(menu.jsp)中修改提交路径

编写CustomerAction中的saveUI方法

配置页面跳转

修改客户添加页面

完成客户保存操作

编写dao层

首先,我们在com.meimeixia.dao包下创建一个CustomerDao接口,在该接口中添加一个保存客户的方法声明,如下:

package com.meimeixia.dao;

import com.meimeixia.domain.Customer;

public interface CustomerDao {

	public void save(Customer customer);
	
}

然后,在com.meimeixia.dao.impl包下编写该接口的一个实现类(CustomerDaoImpl.java)。

package com.meimeixia.dao.impl;

import com.meimeixia.dao.CustomerDao;
import com.meimeixia.domain.Customer;

public class CustomerDaoImpl implements CustomerDao {

	@Override
	public void save(Customer customer) {
		System.out.println("CustomerDaoImpl中的save方法执行了......");
	}

}

接着,将以上实现类交给Spring来管理。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	 
	 <!-- 配置CustomerDao -->
	 <bean id="customerDao" class="com.meimeixia.dao.impl.CustomerDaoImpl">
	 
	 </bean>
	       
</beans>

编写service层

首先,在com.meimeixia.service包下创建一个CustomerService接口,在该接口中添加一个保存客户的方法声明,如下:

package com.meimeixia.service;

import com.meimeixia.domain.Customer;

public interface CustomerService {
	
	public void save(Customer customer);

}

然后,在com.meimeixia.service.impl包下编写CustomerService接口的一个实现类——CustomerSeviceImpl.java。

package com.meimeixia.service.impl;

import com.meimeixia.dao.CustomerDao;
import com.meimeixia.domain.Customer;
import com.meimeixia.service.CustomerService;

public class CustomerServiceImpl implements CustomerService {
	
	private CustomerDao customerDao;
	
	public void setCustomerDao(CustomerDao customerDao) {
		this.customerDao = customerDao;
	}

	@Override
	public void save(Customer customer) {
		System.out.println("CustomerServiceImpl的save方法执行了......");
		customerDao.save(customer);
	}

}

接着,将以上实现类交给Spring来管理。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	 
	 <!-- 配置CustomerService -->
	 <bean id="customerService" class="com.meimeixia.service.impl.CustomerServiceImpl">
	 	<!-- 注入customerDao属性 -->
	 	<property name="customerDao" ref="customerDao"></property>
	 </bean>
	 
	 <!-- 配置CustomerDao -->
	 <bean id="customerDao" class="com.meimeixia.dao.impl.CustomerDaoImpl">
	 
	 </bean>
	       
</beans>

编写CustomerAction中的save方法

package com.meimeixia.web.action;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.meimeixia.domain.Customer;
import com.meimeixia.service.CustomerService;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

public class CustomerAction extends ActionSupport implements ModelDriven<Customer> {

	//模型驱动使用的对象
	private Customer customer = new Customer();
	
	@Override
	public Customer getModel() {
		return customer;
	}
	
	/* * 跳转到客户添加页面的方法:saveUI */
	public String saveUI() {
		return "saveUI";
	}
	
	/* * 编写保存客户的方法 */
	public String save() {
		//创建一个工厂类
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		CustomerService customerService = (CustomerService) applicationContext.getBean("customerService");
		System.out.println("CustomerAction中的save方法执行了......");
		customerService.save(customer);
		return NONE;
	}

}

试想一下,以上CustomerAction类可不可以像下面这样写?即把CustomerAction类交给Spring来管理,然后通过set方法的方式注入CustomerService类型的属性。

现在在CustomerAction里面,是不能这么干的!因为我们的CustomerAction不是Spring框架创建的,它是由Struts2这个框架创建的,所以就不能通过set方法的方式注入CustomerService类型的属性了。

测试程序

发布我们的项目到Tomcat服务器并启动,然后访问该项目的首页,点击新增客户超链接,紧接着直接点击保存按钮,这时,你就会发现Eclipse控制台打印了如下内容。

这就说明咱们的保存客户的操作就跑通了。

Spring整合web项目

问题描述

如果多次点击保存按钮,那么你就会发现Eclipse控制台打印了如下内容。

这就产生了一个问题:由于Action对象是一个多实例的对象,所以每次请求访问Action都会创建一个Action对象,相应地每次请求访问都会创建一个Spring的工厂类对象,这样就会特别浪费服务器的资源,而且这个工厂类对象在Spring里面应该是最耗资源的一个对象了。所以,一个项目应该只有一个Spring的工厂类对象。

解决方案:使用Spring核心监听器ContextLoaderListener来整合web项目

Spring整合web项目的思想

在服务器启动的时候,创建一个Spring工厂类的对象,创建完之后,将这个工厂类的对象保存到ServletContext中,每次获取工厂类的对象使用时都从ServletContext中获取。

Spring整合web项目的底层原理

Spring整合web项目用到以下两个技术:

  • ServletContext对象:它在服务器启动时就会创建;
  • ServletContextListener监听器:它用于监听ServletContext对象的创建和销毁。在服务器启动的时候,每个项目都会创建一个ServletContext对象,而且每个项目只有一个ServletContext对象。在ServletContext对象创建的时候,使用监听器可以监听到其创建。当我们监听到ServletContext对象创建时,Spring就会帮我们做一件事情——加载Spring配置文件,并把配置文件中的对象进行创建,对象创建之后,放到ServletContext域里面去,最终我们要使用创建的对象,可从ServletContext域里面获取出来。

Spring整合web项目的实现

在服务器启动的时候,每个项目都会创建一个ServletContext对象,使用监听器可以知道ServletContext对象在什么时候创建,然后加载Spring配置文件,创建配置的对象,并把创建的对象放到ServletContext域里面。但是,在Spring里面不需要我们写这些操作的代码了,因为它已经帮我们进行了封装,Spring里面封装了一个监听器,我们只需要配置监听器就可以了。使用Spring里面的监听器时,需要导入一个jar包,这个jar包用于整合web项目。

接着,在web.xml文件中配置Spring里面的监听器(ContextLoaderListener),这样在服务器启动的时候,它就会加载Spring的配置文件了。ContextLoaderListener实现了ServletContextListener接口,而且它默认加载的是工程下的/WEB-INF/applicationContext.xml配置文件,所以,我们就要手动配置让其加载类路径下的配置文件。

紧接着,通过WebApplicationContextUtils工具类在Action中获取工厂。

这样,问题就得到解决了,这时一个项目中就只有一个Spring工厂类的对象了。

相关文章