文章目录
1.写在前面
spring的作用
传统设计举例:
一个类Person,另一个类Car,如果Person的某个方法比如说drive,需要引用Car,则称Person类依赖于 Car类。
延伸到对象,比如Person类的对象boy依赖于Car类的对象toyota,这种依赖关系依然成立。
而在控制反转(IoC)模式下:
创建被调用者的工作不再由调用者来完成,两者之间的依赖关系由Spring管理,使得两者解耦;
【也即不希望以上面例子中的person类去new一个car类的实例,而是添加一个set方法】
对控制反转的理解
控制反转其实是从依赖一个实体类转为依赖接口。这样做的好处在于可以装配接口的不同具体实现。
2.一个非常简单的spring例子(由依赖类到依赖接口)
导入spring的4个基础jar包以及common-logging-1.2.jar
spring包下载地址
找到对应版本点击之后下载spring-framework-x.x.x.RELEASE-dist.zip就可以了
在这里我也附一个自己的网盘下载链接,5.1.2版本的:网盘链接 提取码lwmp
在这里需要导入的四个基础jar包:
不要忘了导入common-logging-1.2.jar噢
抽象接口 ICustomerDao.java
package com.test.dao;
public interface ICustomerDao {
public void save();
}
实现类 CustomerDao.java
package com.test.dao;
public class CustomerDao implements ICustomerDao {
public CustomerDao() {
// TODO Auto-generated constructor stub
System.out.println("create CustomerDao.");
}
@Override
public void save() {
// TODO Auto-generated method stub
System.out.println("execute --save()-- method.");
}
}
配置文件 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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="userDAO" class="cn.edu.zjut.dao.CustomerDao" />
</beans>
测试代码
spring是非侵入式框架,也就是说除了测试代码之外的所有程序代码中都不会有spring组件。
在这里我们可以看到它使用了getBean("userDAO")
获取实例,这里双引号中的内容是userDao是参考applicationContext.xml中的bean id的内容。
package com.test.app;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.edu.zjut.dao.ICustomerDao;
public class SpringEnvTest {
public static void main(String[] args) {
//创建Spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext( "applicationContext.xml");
//获取CustomerDAO实例
ICustomerDao userDao = (ICustomerDao) ctx.getBean("userDAO");
userDao.save();
}
}
3.ssh框架整合
a. 将需要的包导入到web-inf的lib目录中
【hibernate相关】
导入hibernate5-required中的包:网盘链接
提取码:a7dw
【struts相关】
之前写struts时用到的包:
除此之外还需要用到一个新的包:struts2-spring-plugin-x.x.x
若是没有这个包会报错的!!
【spring相关】
基础包:比上面的简单例子多了一个spring-web包
还有三个与数据库相关的jar包:
b. spring整合hibernate
①po下的文件无变化(Customer.java和Customer.hbm.xml)
Customer.java
package cn.edu.zjut.po;
import java.io.Serializable;
import java.util.Date;
public class Customer implements Serializable {
public Customer() {
// TODO Auto-generated constructor stub
}
private int customerId;
private String account;
private String password;
private String name;
private Boolean sex;
private Date birthday;
private String phone;
private String email;
private String address;
private String zipcode;
private String fax;
public Customer(int customerId, String account, String password, String name, Boolean sex, Date birthday,
String phone, String email, String address, String zipcode, String fax) {
super();
this.customerId = customerId;
this.account = account;
this.password = password;
this.name = name;
this.sex = sex;
this.birthday = birthday;
this.phone = phone;
this.email = email;
this.address = address;
this.zipcode = zipcode;
this.fax = fax;
}
public Customer(int customerId) {
super();
this.customerId = customerId;
}
public int getCustomerId() {
return customerId;
}
public void setCustomerId(int customerId) {
this.customerId = customerId;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getSex() {
return sex;
}
public void setSex(Boolean sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
public String getFax() {
return fax;
}
public void setFax(String fax) {
this.fax = fax;
}
}
Customer.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="cn.edu.zjut.po.Customer" table="customer" schema="dbo">
<id name="customerId" type="java.lang.Integer">
<column name="customerID" />
<generator class="increment" />
</id>
<property name="account" type="java.lang.String">
<column name="account" length="20" unique="true" />
</property>
<property name="password" type="java.lang.String">
<column name="password" length="20" />
</property>
<property name="name" type="java.lang.String">
<column name="name" length="20"></column>
</property>
<property name="sex" type="java.lang.Boolean">
<column name="sex" />
</property>
<property name="birthday" type="date">
<column name="birthday" length="10" />
</property>
<property name="phone" type="java.lang.String">
<column name="phone" length="20" />
</property>
<property name="email" type="java.lang.String">
<column name="email" length="100" />
</property>
<property name="address" type="java.lang.String">
<column name="address" length="200" />
</property>
<property name="zipcode" type="java.lang.String">
<column name="zipcode" length="10" />
</property>
<property name="fax" type="java.lang.String">
<column name="fax" length="20" />
</property>
</class>
</hibernate-mapping>
②BaseHibernateDao.java
package cn.edu.zjut.dao;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
public class BaseHibernateDao {
private SessionFactory sessionFactory;
public Session getSession() {
return sessionFactory.openSession();
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
③抽象出来的接口ICustomerDao.java
package cn.edu.zjut.dao;
import cn.edu.zjut.po.Customer;
public interface ICustomerDao {
public void save(Customer aCus);
}
④CustomerDao.java-实现ICustomerDao接口并继承 BaseHibernateDao
package cn.edu.zjut.dao;
import org.hibernate.Session;
import org.hibernate.Transaction;
import cn.edu.zjut.po.Customer;
public class CustomerDao extends BaseHibernateDao implements ICustomerDao {
public CustomerDao() {
// TODO Auto-generated constructor stub
System.out.println("create CustomerDao.");
}
@Override
public void save(Customer aCus) {
// TODO Auto-generated method stub
Transaction tran = null;
Session session = null;
try {
session = getSession();
tran = session.beginTransaction();
session.save(aCus);
tran.commit();
} catch (RuntimeException re) {
if(tran != null)
tran.rollback();
throw re;
} finally {
session.close();
}
}
}
⑤UserService.java及其抽象出来的接口IUserService.java
IUserService.java:
package cn.edu.zjut.service;
import cn.edu.zjut.po.Customer;
public interface IUserService {
public void register(Customer aCus);
}
UserService.java:
这里依赖CustomerDao,但是并没有去new它,而是提供了一个set方法。
为什么不用提供Customer的私有属性和set方法?因为它是由上一层传参进来的,原来也并不需要在这里new
package cn.edu.zjut.service;
import cn.edu.zjut.dao.ICustomerDao;
import cn.edu.zjut.po.Customer;
public class UserService implements IUserService {
private ICustomerDao customerDao = null;
public UserService() {
// TODO Auto-generated constructor stub
System.out.println("create UserService.");
}
public void setCustomerDao(ICustomerDao customerDao) {
System.out.println("--setCustomerDAO--");
this.customerDao = customerDao;
}
@Override
public void register(Customer aCus) {
// TODO Auto-generated method stub
System.out.println("execute --register()-- method.");
customerDao.save(aCus);
}
}
⑥spring配置文件applicationContext.xml
理一下上面这些类的依赖关系:UserService依赖CustomerDao,CustomerDao依赖Customer。
由于CustomerDao没有和Customer有关的属性,因此不需要在<bean></bean>
中间写property。
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="jdbc:sqlserver://localhost:1433;DatabaseName=hibernatedb"/>
<property name="username" value="sa"/>
<property name="password" value="123456"/>
</bean>
<!-- 把数据源注入给session工厂 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 配置映射文件 -->
<property name="mappingResources">
<list>
<value>cn/edu/zjut/po/Customer.hbm.xml</value>
</list>
</property>
</bean>
<!-- 把dao注册给session工厂 -->
<bean id="baseDao" class="cn.edu.zjut.dao.BaseHibernateDao">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="userDAO" class="cn.edu.zjut.dao.CustomerDao" parent="baseDao"/>
<bean id="userService" class="cn.edu.zjut.service.UserService">
<property name="customerDao" ref="userDAO" />
</bean>
</beans>
注意这里在把数据源注入给session工厂的时候class是org.springframework.orm.hibernate5.LocalSessionFactoryBean,是因为这里是spring5,如果用的是spring4,那么这里要改成hibernate4。另外不要尝试用hibernate4搭配spring5这样…因为spring5用的是hibernate5,而hibernate4和5中有些jar包中类的位置是不一样的,很容易就classNotFound.
c. spring整合Struts
①UserAction.java——不再new它的依赖类
依赖UserService.java和Customer.java.同样的这里也并没有去直接new一个UserService对象或者Customer对象,而是提供了set方法。
package cn.edu.zjut.action;
import cn.edu.zjut.po.Customer;
import cn.edu.zjut.service.IUserService;
public class UserAction {
private Customer loginUser;
private IUserService userService = null;
public Customer getLoginUser() {
return loginUser;
}
public void setLoginUser(Customer loginUser) {
this.loginUser = loginUser;
}
public void setUserService(IUserService userService) {
this.userService = userService;
}
public String execute() {
userService.register(loginUser);
return "success";
}
}
②为UserAction增加applicationContext.xml中的内容
增加内容:
注意action的scope必须是prototype(这个在后面的博客中会解释)
那么为什么对于UserAction来说,它不仅依赖UserService,也依赖Customer,这里却没有customer的property呢?
因为action里的customer并不是由spring装配的,而是由struts装配的,因为它是从表单传过来的呀!
<bean id="userAction" class="cn.edu.zjut.action.UserAction" scope="prototype">
<property name="userService" ref="userService" />
</bean>
③src下的struts.xml,一点点小变化
struts.xml:
变化在于class这里,不再是完整的包名.类名,而是使用了userAction,而这个userAction是在applicationContext.xml中规定的bean的id
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="strutsBean" extends="struts-default" namespace="/">
<action name="register" class="userAction">
<result name="success">/regSuccess.jsp</result>
<result name="fail">/regFail.jsp</result>
</action>
</package>
</struts>
④web.xml——需要添加对spring监听器的配置
在这里配置监听器的作用:在启动Web容器时,自动装配spring applicationContext.xml的配置信息。
因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。在ContextLoaderListener中关联了ContextLoader这个类,所以整个加载配置过程由ContextLoader来完成。
如果不配置监听器这里会报错:userAction not found
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<!-- 让Struts2的核心Filter拦截所有请求 -->
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 这个在这里可以不写 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/applicationContext.xml</param-value>
</context-param>
<!-- 配置监听器 -->
<listener>
<listener-class> org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
⑤register.jsp和regSuccess.jsp——无变化
register.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ taglib prefix="sx" uri="/struts-dojo-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<s:head theme="xhtml"/>
<sx:head parseContent="true" extraLocales="UTF-8"/>
</head>
<body>
<s:form action="register" method="post">
<s:textfield name="loginUser.account" label="请输入用户名" />
<s:password name="loginUser.password" label="请输入密码" />
<s:textfield name="loginUser.name" label="请输入真实姓名" />
<s:radio name="loginUser.sex" list="#{true:'男',false:'女'}" label="请输入性别" />
<sx:datetimepicker name="loginUser.birthday" displayFormat="yyyy-MM-dd" label="请输入生日" />
<s:textfield name="loginUser.address" label="请输入联系地址" />
<s:textfield name="loginUser.phone" label="请输入联系电话" />
<s:textfield name="loginUser.email" label="请输入电子邮箱" />
<s:textfield name="loginUser.zipcode" label="请输入邮编" />
<s:textfield name="loginUser.fax" label="请输入传真" />
<s:submit value="注册" />
<s:reset value="重置"/>
</s:form>
</body>
</html>
regSuccess.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>登录成功页面</title>
</head>
<body>
<s:property value="loginUser.name" />
<s:if test="%{loginUser.sex==true}">
<s:text name="先生,"/>
</s:if>
<s:else>
<s:text name="女士,"/>
</s:else>
您注册成功了!
<s:set name="user" value="loginUser" scope="session" />
</body>
</html>
d.关于applicationContext文件的放置位置
spring的配置文件applicationContext.xml的默认地址在WEB-INF下,这时是不用特地在web.xml中标记的。当然如果要标记也可以,就像这样:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/applicationContext.xml</param-value>
</context-param>
但在实际的开发过程中,我们可能需要调整applicationContext.xml的位置,以使程序结构更加的清晰。在web.xml中,配置Spring配置文件的代码如下:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>路径</param-value>
</context-param>
例如我们在最前面写简单的例子的时候,就是把它直接放在src下的,当然这时候不牵涉到struts和hibernate是没有问题的。但是如果我们ssh时想把它放在src下呢?
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>