一、导包
1)Spring
【AOP核心】
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
【IOC核心包】
commons-logging-1.1.3.jar
spring-aop-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
【jdbc核心】
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar
【测试包】
spring-test-4.0.0.RELEASE.jar
2)SpringMVC
【SpringMVC核心包】
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar
【文件上传下载包】
commons-fileupload-1.2.1.jar
commons-io-2.0.jar
【jstl java标准标签库】
jstl.jar
standard.jar
【数据校验包】
hibernate-validator-5.0.0.CR2.jar
hibernate-validator-annotation-processor-5.0.0.CR2.jar
classmate-0.8.0.jar
jboss-logging-3.1.1.GA.jar
validation-api-1.1.0.CR1.jar
【ajax包】
jackson-annotations-2.1.5.jar
jackson-core-2.1.5.jar
jackson-databind-2.1.5.jar
【验证码包】
kaptcha-2.3.2.jar
3)Mybatis
【Mybatis核心包】
mybatis-3.4.1.jar
【Mybatis和Spring的整合包】
mybatis-spring-1.3.0.jar
【ehcache整合】
ehcache-core-2.6.8.jar
log4j.jar
mybatis-ehcache-1.0.3.jar
slf4j-api-1.6.1.jar
slf4j-log4j12-1.6.2.jar
【mysql数据源、数据库驱动包】
mysql-connector-java-8.0.21.jar
c3p0-0.9.1.2.jar
【junit单元测试包】
hamcrest-core-1.3.jar
junit-4.12.jar
二、写配置
1)applicationContext-mvc.xml
①只扫描标了Controller注解的组件
<context:component-scan base-package="com.philshao" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
②配置视图解析器,用于拼接控制器返回的结果字符串,形成完整的文件名
<bean id="internalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置前缀和后缀 -->
<property name="prefix" value="/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
③扫描静态资源
<mvc:default-servlet-handler></mvc:default-servlet-handler>
扫描动态资源
<mvc:annotation-driven></mvc:annotation-driven>
④由于springmvc上下文默认没有配置文件上传解析器,所以需要自己配置,在dispatcher组件multipartResolver进行初始化时,从ioc容器中使用id=multipartResolver进行获取。
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/>
<!--配置上传文件的最大size为20M-->
<property name="maxUploadSize" value="#{1024*1024*20}"/>
</bean>
2)applicationContext.xml
①spring只关注业务逻辑组件,所以只扫描除Controller以外的其余组件
<context:component-scan base-package="com.philshao">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
②导入外部数据库连接配置文件dbconfig.properties
<context:property-placeholder location="classpath:dbconfig.properties"></context:property-placeholder>
#dbconfig.properties
jdbc.username=root
jdbc.password=12345678
jdbc.url=jdbc:mysql:///test
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.maxPoolSize=20
jdbc.minPoolSize=5
然后,配置数据源,这里使用的是开源的jdbc数据库连接池 c3p0
<bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
<property name="minPoolSize" value="${jdbc.minPoolSize}"></property>
</bean>
③配置使用mybatis操作数据库,这里使用到了mybatis和spring的整合包 mybatis-spring-1.3.0.jar
以配置的方式,将mybatis中的sqlSessionFactory放入ioc容器中,sqlSessionFactory可以由其工厂类org.mybatis.spring.SqlSessionFactoryBean通过getObject()方法创建。
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!--指定mybatis全局配置文件的位置,该文件为类路径下(src路径下或Resource Root下为类路径下)的mybatis-config.xml-->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<!--指定数据源为上面配置的c3p0的ds-->
<property name="dataSource" ref="ds"></property>
<!--指定xml映射文件,即dao接口的实现xml文件的位置,这里包括类路径下文件名最后三位为Dao的所有xml文件-->
<property name="mapperLocations" value="classpath:*Dao.xml"></property>
</bean>
以配置的方式,将dao接口的实现,加入到ioc容器中
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定dao接口所在的基础包-->
<property name="basePackage" value="com.philshao.dao"></property>
</bean>
④配置事务控制,配置事务管理器控制住数据源DataSource里面connection的关闭和提交
<bean id="tm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 控制数据源,数据源即上面配置过的 -->
<property name="dataSource" ref="ds"></property>
</bean>
<!--基于xml配置,配置事务-->
<aop:config>
<!--配置切入点表达式,表示哪些方法需要切入事务,expression表示的方法都需要切入事务-->
<!-- * com.philshao.service.*.*(..) 表示任意返回值,service包下的任意类的任意方法,参数也任意 -->
<aop:pointcut id="txPoint" expression="execution(* com.philshao.service.*.*(..))"/>
<!--对于要切入的事务,应该配置什么样的属性-->
<aop:advisor advice-ref="myTx" pointcut-ref="txPoint"/>
</aop:config>
<!--配置事务增强、事务属性、事务建议-->
<tx:advice id="myTx" transaction-manager="tm">
<!--配置事务属性,例如:异常回滚,get方法只读等等-->
<tx:attributes>
<!--所有方法,对于任何异常都回滚-->
<tx:method name="*" rollback-for="java.lang.Exception"/>
<!--所有get方法,都只读-->
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
3)mybatis-config.xml
由于applicationContext.xml已经配置了数据源等信息,并且也注册了dao接口的映射,所以mybatis-config.xml中就只需要配置mybatis自身的一些设置,例如开启二级缓存、懒加载等等。
<settings>
<!-- 开启全局缓存,即二级缓存,当session关闭时,其一级缓存会被转移到二级缓存,供其他session使用 -->
<!-- mybatis查询顺序为:二级缓存 > 一级缓存 > 发送sql查询数据库 -->
<setting name="cacheEnabled" value="true"/>
</settings>
4)dao接口的映射文件
示例代码用了两个bean。
public class User {
private Integer id;
private String name;
private String password;
private String address;
private String phone;
private Department dept;
...
}
public class Department {
private Integer deptId;
private String deptName;
...
}
数据库中包含两张表user表和department表。
user表包含id, name, password, address, phone, dept_id字段。
department表包含dept_id, dept_name字段。
UserDao.java中定义了一些查询方法。
public interface UserDao {
//查询所有用户
public List<User> getUsers();
// 返回的Map中key为对象的id,value为对象User
@MapKey("id")
public Map<Integer,User> getUsersMap();
public User getUserById(Integer id);
//根据范围查询,where id > ? and name like `%i%`之类
public List<User> getUsersByCondition(User user);
//where id in ids 的范围查询
public List<User> getUsersByCollection(@Param("ids") List<Integer> ids);
public int updateUser(User user);
//使用set标签进行部分字段(如果该字段有值)的更新
public int updateUserBySet(User user);
public int deleteUser(Integer id);
public int insertUser(User user);
}
dao接口的映射文件 UserDao.xml
<!--mapping标签的namespace指明用来处理哪个接口,
然后需要在mybatis的全局配置文件mybatis_config.xml进行注册-->
<mapper namespace="com.philshao.dao.UserDao">
<!-- 使用第三方缓存,bean类可以不实现序列化接口 -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
<!-- select标签表示查询操作,id表示对应的查询方法,resultType表示查询的返回值,#{id}表示方法传入的参数-->
<select id="getUserById" resultMap="myUser">
select `id`,`name`,`password`,`address`,`phone`,user.`dept_id`,`dept_name`
from user left join department
on user.dept_id=department.dept_id
where user.`id`=#{id}
</select>
<!-- public List<User> getUsersByCondition(User user);
where标签会将前面多余的 and 去除 -->
<select id="getUsersByCondition" resultMap="myUser">
select `id`,`name`,`password`,`address`,`phone`,user.`dept_id`,`dept_name`
from user left join department
on user.dept_id=department.dept_id
<where>
<if test="id != null">
id > #{id}
</if>
<if test="name != null">
and name like #{name}
</if>
<if test="address != null">
and address like #{address}
</if>
</where>
</select>
<!-- public List<User> getUsersByCollection(List<Integer> ids); -->
<select id="getUsersByCollection" resultMap="myUser">
select `id`,`name`,`password`,`address`,`phone`,user.`dept_id`,`dept_name`
from user left join department
on user.dept_id=department.dept_id
where id in
<foreach collection="ids" open="(" close=")" item="id" separator=",">
#{id}
</foreach>
</select>
<resultMap id="myUser" type="com.philshao.pojo.User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="password" column="password"/>
<result property="address" column="address"/>
<result property="phone" column="phone"/>
<association property="dept" javaType="com.philshao.pojo.Department">
<id property="deptId" column="dept_id"/>
<result property="deptName" column="dept_name"/>
</association>
</resultMap>
<!-- public User getUsers(),返回值必须写容器中元素的类型-->
<select id="getUsers" resultType="com.philshao.pojo.User">
select * from user
</select>
<!-- public Map<Integer,User> getUsersMap(),返回值类型必须写容器中value的类型-->
<select id="getUsersMap" resultType="com.philshao.pojo.User">
select * from user
</select>
<!-- 增删改不用填写返回值类型,mybatis自动判断,
如果原方法的返回值类型是数值,则返回影响的行数;如果是布尔类型,则返回是否成功-->
<update id="updateUser">
update user
set name=#{name},password=#{password},address=#{address},phone=#{phone}
where id=#{id}
</update>
<!-- public int updateUserBySet(User user); 使用set标签更新数据库 -->
<update id="updateUserBySet">
update user
<set>
<if test="name != null">
name=#{name},
</if>
<if test="address != null">
address=#{address},
</if>
<if test="password != null">
password=#{password}
</if>
</set>
<where>id=#{id}</where>
</update>
<!--添加数据-->
<insert id="insertUser">
insert into user (`name`,`password`,`address`,`phone`)
values (#{name},#{password},#{address},#{phone})
</insert>
<!--删除数据-->
<delete id="deleteUser">
delete from user where id=#{id}
</delete>
</mapper>
三、测试SSM
1)首页index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<a href="getUser?id=1">点击查询id为1的用户</a>
</body>
</html>
2)测试成功页success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>访问成功</title>
</head>
<body>
<h1>success</h1>
${requestScope.user.name}<br/>
${requestScope.user.address}
</body>
</html>
3)前端控制器 UserController
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/getUser")
public String getUser(@RequestParam("id")Integer id, Model model){
User user = userService.getUser(id);
model.addAttribute("user",user);
return "success";
}
}
4)业务逻辑组件 UserService
@Service
public class UserService {
@Autowired
private UserDao userDao;
public User getUser(Integer id){
return userDao.getUserById(id);
}
}
然后就可以启动开始测试。