此文参考书籍为ACCP软件工程师——使用SSM框架开发企业级应用 8.0版
MyBatis(Dao层部分)
MyBatis传入参数的时候都会将参数放在一个Map中,返回值也是无论你设置的是resultTpye还是resultMap,其实他都会返回一个Map
一、知识了解
(1)核心接口和类
①sqlSessionFactoryBuilder(书P21):用过即丢,作用于方法体内,接收mybatis-config.xml形成的流或类,创建sqlSessionFactory。
②sqlSessionFactory:作用域是整个应用,是创建sqlSession实例的工厂
③sqlSession:最佳作用域是request作用域或者方法体作用域内,类似于connection。用来直接运行已经映射的SQL语句(P24下和P25下)
(2)MyBatis核心配置文件(mybatis-config.xml)
(3)SQL映射文件(mapper.xml)
(4)mybatis缓存
参考链接:mybatis 缓存的使用, 看这篇就够了
SSM框架搭建](https://blog.csdn.net/weixin_43773038/article/details/105372591)
MyBatis提供了一级缓存和二级缓存,书上写了解即可(只是说MyBatis的缓存容器了解即可,但是缓存机制得明白),缓存用OSCache、Memcached等缓存服务器更为合理。
二、详细配置
1.mybatis-config.xml
(1)配置properties:有两种写法,直接在这个xml文件中写,或者新建一个配置文件database.properties(是个file类型的文件)
参考链接:java的properties文件怎么创建?
(2)typeAliases元素(书P29):
作用是配置类型别名,就是把mapper的resultType的很长的名字,在mybatis-config.xml中配置用简单名字进行代替(例如:Pojo.User如果结构更深的话,就更复杂)。这里应该那个mapper.xml文件的namespace中的路径也可以用这个来进行简化 这里只能对javaBean进行设置别名。
三种方式:
①<typeAlias alias=“User” type=“Pojo.User” />
②<package name=“Pojo” />
这里用package的name属性标记包名,MyBatis会自动扫描包下的JavaBean,并默认设置一个别名,默认为JavaBean的非限定类名
③在User.java中直接用@Alias(value=“User”)
参考链接:MyBatis中关于别名typeAliases的设置
2.PojoMapper.xml
(1)通过配置resultMap实现高级结果映射
(2)使用@Param注解实现多参数入参
有时候只需要向PojoMapper.xml文件传入两个简单参数(一般超过四个参数最好封装成对象),没有必要传入整个例如Pojo的类,而xml中的resultType还不能实现两个参数,所以就需要在PojoMapper.java 文件中设定方法时使用@Param注解实现多参数传入。
此种方式可读性高。
例如:
在UserMapper.xml文件中
<update id="setPasswordById">
UPDATE user
SET password=#{password}
WHERE id=#{id}
</update>
在UserMapper.java中
public int setPasswordById(@Param("id")int user_id,@Param("password")String password); //通过用户id修改用户密码
(3)动态SQL——if、where、set、trim实现动态查询,更新
用动态SQL语言来解决JDBC时,将条件字符串连接成SQL字符串的空格和大堆的if-else问题
这里的例子只是为了说明标签的作用,实际上修改用户,有时候会需要将某一项请空的需求,可以在修改页面进入时就用POST请求给所有的标签默认值,并且不用防止null传入
①if
举例:
函数功能如果传入的参数username不为空那么就使第一个if标签中语句有效,第二个标签同理,但是如果第一个标签无效第二个标签有效就会导致SQL语句出错(因为WHERE后面紧接着AND),所以引入where标签
<!-- 函数功能如果传入的参数username不为空那么就使第一个if标签中语句有效,第二个标签同理 -->
<!-- 但是如果第一个标签无效第二个标签有效就会导致SQL语句出错(因为WHERE后面紧接着AND),所以引入where标签 -->
<select id="getUserList" resultType="User">
SELECT * FROM user WHERE
<if test="username != null and username != ''">
username LIKE CONCAT ('%',#{username},'%')
</if>
<if test="favorite_id != null and favorite_id != ''">
AND favorite_id = #{favorite_id}
</if>
</select>
②where
where元素主要用来简化SQL语句中的where条件判断,并能智能地处理and和or,不必担心多于关键字导致的语法错误。
<!--where元素主要用来简化SQL语句中的where条件判断,并能智能地处理and和or,不必担心多于关键字导致的语法错误。 -->
<!-- 这里如果第一个if标签无效第二个if标签有效,那么where标签会自动的消除第二个if标签SQL语句的AND -->
<select id="getUserList" resultType="User">
SELECT * FROM user WHERE
<where>
<if test="username != null and username != ''">
username LIKE CONCAT ('%',#{username},'%')
</if>
<if test="favorite_id != null and favorite_id != ''">
ANDfavorite_id = #{favorite_id}
</if>
</where>
</select>
③set
即例如更新用户数据表时,若某个参数传入值为null时,不需要set该字段
而且注意每句话后面都需要有”,“来保证SQL语言的正确性,但是如果设定最后一个if标签中没有”,“的话,当此标签失效的时候还是会在末尾出现错误,而set可以将末尾的逗号忽略掉,而且if标签中语句保持一致方便以后的修改增加
<select id="modify" resultType="User">
UPDATE user
<set>
<if test="username != null and username != ''"> username=#{usernaem}, </if>
<if test="telephone != null and telephone != ''"> telephone=#{telephone}, </if>
<if test="email != null and email != ''"> email=#{email}, </if>
<if test="introduce != null and introduce != ''"> introduce=#{introduce}, </if>
</set>
</select>
④trim
tirm元素会自动识别标签内是否有换回之,如果有就会在内容前面加上某些前缀(prefix)或者后缀(suffix),也可以把包含内容的首部或者尾部的内容覆盖掉,举例如下
<!-- 这里是和起到和②中一样的作用 -->
<select id="getUserList" resultType="User">
SELECT * FROM user WHERE
<trim prefix="WHERE" prefixOverrides="and | or"> <!-- 如果标签内的任何一个if标签有效,即标签内有返回值,则个标签中内容填上一个前缀(prefix)——WHERE,并且会自动消除与prefix中内容紧靠的prefixOverrides中的元素 -->
<if test="username != null and username != ''">
username like CONCAT ('%',#{username},'%')
</if>
<if test="favorite_id != null and favorite_id != ''">
and favorite_id = #{favorite_id}
</if>
</trim>
</select>
(4)使用foreach完成复杂查询
可以接收入参为数组、list或者Map类型的(数组和list不同点就是collection的参数类型不同)
其中元素
item:表示集合中每个元素进行迭代时的别名,此处为roleIds
open:表示语句以什么开始(in语句就是in (value1,value2),所以是"(“为开始的,以”,"为间隔符的)
separator:表示每次迭代之间以什么符号为分隔符(而且能只能处理分隔符不会出现多余的分隔符)
close:表示语句以什么为结束
collection:指定参数格式
如果参数为单参数且参数是一个List的时候,其属性为list
如果参数为单参数且参数是一个数组的话,其属性为array(此处就是array)
如果参数是多参数,就需要把他们封装成一个Map进行处理
传入数组和list的时候
<!-- 方法功能是传入一个roleid构成的数组,查询用户属性roleId在这个数组中的用户信息 -->
<select id="getUserByRoleId_foreach_array" resultMap="userMapByRole">
SELECT * FROM user WHERE userRole in
<foreach collection="array" item="roleIds" open="(" separator="," close=")">
#{roleIds}
</foreach>
</select>
<resultMap type="User" id="userMapByRole">
<id property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>
</resultMap>
传入Map的时候
测试类中
Map<String,Object> conditionMap = new HashMap<String,Object>();
List<Integer> rolelist = new ArrayList<Integer>();
roleList.add(2);
roleList.add(3);
conditionMap.put("gender","男");
conditionMap.put("roleIds",roleList);
List<User> users = new ArrayList<User>();
users = sqlSession.getMapper(UserMapper.class).getUserByConditionMap_foreach_map(conditionMap);
PojoMapper.java中
public List<User> getUserByConditionMap_foreach_map(Map<String,Object> conditionMap);
PojoMapper.xml文件
<select id="getUserByConditionMap_foreach_map" resultMap="userMapByRole">
SELECT * FROM user WHERE gender=#{gender} AND userRole in
<foreach collection="roleIds" item="roleMap" open="(" separator="," close=")">
<!-- 这里的collection属性值是传入的变量的名字 -->
#{roleMap}
</foreach>
</select>
<resultMap type="User" id="userMapByRole">
<id property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>
</resultMap>
(5)choose(when、otherwise)——多个参数选其一使用完成查询
元素
when:当其test中条件满足的时候就会输出when元素中的内容。并且当when中一旦有条件满足的时候,就会跳出choose,及所有的when和otherwise条件中,只有一个条件会输出。
otherwise:当when中的所有条件都不满足的时候,就会自动输出otherwise元素中的内容。
UserMapper.xml文件
<!-- 方法功能当username、introduce和userrole以从上到下的顺序,第一个有效的when标签生效,即跳出choose标签,如果都没有生效则otherwise标签生效 -->
<select id="getUserList_choose" resultType="User">
SELECT * FROM user WHERE 1=1
<choose>
<when test="username != null and username != ''">
AND username LIKE CONCAT ('%',#{username},'%')
</when>
<when test="introduce != null and introduce != ''">
AND introduce LIKE CONCAT ('%',#{introduce},'%')
</when>
<when test="userrole != null">
AND userrole=#{userrole}
</when>
<otherwise>
AND registTime = #{registTime}
</otherwise>
</choose>
</select>
UserMapper.java文件
public List<User> getUserList_choose(@Param("username")String username,@Param("introduce")String introduce,@Param("userrole")String userrole,@Param("registTime")Date registTime);
(5)标签中的各个参数
公共参数:
<insert>中:
keyproperty:
<!-- 使用 keyProperty="id" useGeneratedKeys="true"可以在使用addUser时,自动返回id-->
<insert id="addUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (username,password,gender,email,telephone,introduce,activeCode,role,registTime)
VALUES(#{username},#{password},#{gender},#{email},#{telephone},#{introduce},#{activeCode},#{role},#{registTime})
</insert>
3.MyBatisUtils.java
(1)如果使用inset、update或者delete等会对数据库数据进行修改的语句,需要保持数据的一致性
所以需要在此处开启Session的时候,设置为手动提交事务,并在调用的时候用commit()进行提交并在失败出错时用rollback()进行回滚,保持数据的一致性。
举例如下:
//MyBatisUtil.java中设置事务手动提交
public static SqlSession createSqlSession() {
return factory.openSession(false); //true为自动提交事务
}
//调用时需要做的顺序
try {
sqlSession = MyBatisUtil.createSqlSession();
count = sqlSession.getMapper(UserMapper.class).addUser(user);
sqlSession.commit();
//如果没有异常的话就提交修改,否则用roolback回滚,因为在MyBatisUtils中设置的是
//return factory.openSession(false); //true为自动提交事务,这样就可以判断是否出现异常而来决定是否提交
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
sqlSession.rollback(); //如果出现异常,进行回滚保持数据一致性
count = 0;
}finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
(2)
三、log4j
1.知识了解
也见2.
2.详细配置
参考链接:Log4j配置详解这个链接中的二、是详细配置,注意其中的红色字体是配置格式
实现保存日志路径为相对路径 尝试方法三,最后部署在服务器上的时候试一试服务器环境变量,但是这样好像增加耦合了
log4j配置和Java中调用getlogger()中填写的name的关系这里暂时理解为如果没有额外的名字的话,调用的时候直接用“rootCategory”来填写为name,就可以
3.使用
//这里的debug和info是作为日志记录的级别,也就是优先级,这里的东西如果高于properties中的级别,在哪里输出依赖于配置文件中的appendername是否设置含有那几个class name 例如:consleAppender(控制台输出)
logger.debug(" User's aname:" + user.getUsername()); //这个是指定此信息为debug级别,这里的debug级别呗屏蔽,不进行输出和记录
logger.info(" User's bname:" + user.getUsername()); //这个是指定此信息为info级别,这里的info级别信息,会正常被处理不会被屏蔽
参考配置:用logger在控制台打印信息
Spring(Service部分)
一、知识了解
1.主要特性
有简单性、可测试性和松耦性,是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。
2.优点:
(1)面向接口编程,而不是针对类,而Spring用容器来实现接口的实现和管理来将接口的复杂度降到零。
(2)代码更易于测试。因为具有插拔性,可以根据测试来另外实现,方便测试。
(3)JavaBean提供了应用程序配置的最好方法。?????????
(4)在Java中,已检查异常(Checked exception)被过度使用。框架不应该迫使你捕获不能恢复的异常。??????????????
3.关于增强类
(具体实现在下面二、2.)
(1)前置增强:在方法运行前进行插入运行
(2)后置增强:在方法运行结束进行运行
(3)异常抛出增强:特点是在目标方法抛出异常时织入增强处理,使异常抛出增强
(4)最终增强:特点是无论方法抛出异常还是正常退出,该增强都会得到执行,类似于异常处理机制中finally的作用,一般用于释放资源。
(5)环绕增强:在目标的方法的前后都可以织入增强处理。是最强大的增强处理,它有对目标方法的控制权。(可以修改目标方法的参数、返回值,也可以进行异常处理,也可以决定方法是否被执行)
二、详细配置
1.applicationContext.xml
其中关键字:
(1)<bean>
<!-- 对相关组件机型声明,注意最好不要和PojoMapper.xml中的bean重名 -->
<!-- 这里就能体现出来控制反转的思想,接口类的实现被Spring管理 -->
<bean id="userService" class="service.UserServiceImpl"></bean>
<bean id="theLogger" class="service.UserServiceLogger"></bean>
<!-- 如果实现类需要调用另一个bean的话,写法如下,UserServiceImpl代码见下 -->
<bean id="dao" class="dao.Impl.UserDaoImpl"></bean>
<bean id="userService" class="service.Impl.UserServiceImpl">
<property name="dao" ref="dao"></property>
</bean>
public class UserServiceImpl implements UserService {
private UserDao dao;
......
}
(2)<aop>
参考书P141
<aop:config>
<!-- 定义切入点表达式 ,命名为pointcut -->
<aop:pointcut id="pointcut" expression="execution(public int addUser(Pojo.User))"/>
<!-- <aop:pointcut id="pointcut" expression="execution(* service.UserService.addUser())"/> -->
<!-- 引用包含增强方法的Bean -->
<aop:aspect ref="theLogger">
<!-- 这里的before和afterReturning是在增强类中编写的,代码见下 -->
<!-- 将before()方法定义为前置增强并引用pointcut切入点 -->
<aop:before method="before" pointcut-ref="pointcut"/>
<!-- 将afterReturning()方法定义为后置增强并引用pointcut切入点 -->
<!-- 通过returning属性指定名为result的参数注入返回值 -->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
</aop:aspect>
</aop:config>
这里的execution是切入点指示符,括号中是一个切入点表达式,支持模糊匹配,例如;
①public * addNewUser(entity.User); "*"表示匹配所有类型的返回值
②public void * (entity.User); 表示匹配所有参数为User类的方法。
③public void addNewUser(…); 表示匹配所有参数个数和类型的addNewUser方法
④* com.service.*.*(…); 表示匹配com.service包下所有类的所有方法
⑤* com.service…*.*(…); 表示匹配com.service包及其子包下所有类的所有方法
增强类:
package service;
import java.util.Arrays;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
public class UserServiceLogger {
private static final Logger logger = Logger.getLogger("rootCategory");
//代表前置增强方法
public void before(JoinPoint jp) {
logger.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法入参:" + Arrays.toString(jp.getArgs()));
}
//代表后置增强方法
public void afterReturning(JoinPoint jp,Object result) {
logger.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法返回值:" + result);
}
}
2.关于增强类的实现
(1)前置增强、后置增强(注释实现):
需要配置applicationContext.xml文件:
<!-- 这里是用注释来实现增强的时候用的 -->
<bean class="aop.UserServiceLogger_annotation"></bean>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
package aop;
import java.util.Arrays;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class UserServiceLogger_annotation {
private static final Logger logger = Logger.getLogger("rootCategory");
//代表前置增强方法
@Before("execution(public int addUser(Pojo.User))")
public void before(JoinPoint jp) {
logger.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法入参:" + Arrays.toString(jp.getArgs()));
}
//代表后置增强方法
@AfterReturning(pointcut = "execution(public int addUser(Pojo.User))",returning = "result")
public void afterReturning(JoinPoint jp,Object result) {
logger.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法返回值:" + result);
}
}
(2)前置增强、后置增强(xml配置文件实现):
package aop;
import java.util.Arrays;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
public class UserServiceLogger {
private static final Logger logger = Logger.getLogger("rootCategory");
//代表前置增强方法
public void before(JoinPoint jp) {
logger.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法入参:" + Arrays.toString(jp.getArgs()));
}
//代表后置增强方法
public void afterReturning(JoinPoint jp,Object result) {
logger.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法返回值:" + result);
}
}
<!-- 暂时理解为: 和书上不一样是因为我实现Dao层中接口是用UserMapper.xml实现的,所以不用再次在这里进行设置 -->
<bean id="userMapper" class="dao.UserMapper"></bean>
<bean id="userService" class="service.UserServiceImpl"></bean>
<bean id="theLogger" class="aop.UserServiceLogger"></bean>
<aop:config>
定义切入点表达式 ,命名为pointcut
<aop:pointcut id="pointcut" expression="execution(public int addUser(Pojo.User))"/>
<aop:pointcut id="pointcut" expression="execution(* service.UserService.addUser())"/>
引用包含增强方法的Bean
<aop:aspect ref="theLogger">
将before()方法定义为前置增强并引用pointcut切入点
<aop:before method="before" pointcut-ref="pointcut"/>
将afterReturning()方法定义为后置增强并引用pointcut切入点
通过returning属性指定名为result的参数注入返回值
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
</aop:aspect>
</aop:config>
(3)异常抛出增强:
一般放入资源释放类,因为不管完没有完成都会执行
切入点什么的和(2)的前后增强类似,不再赘述。
xml中关键代码:
<bean id="theLogger" class="aop.ErrorLogger"></bean>
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>
package aop;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
public class ErrorLogger {
private static final Logger logger = Logger.getLogger(ErrorLogger.class);
public void afterThrowing(JoinPoint jp,RuntimeException e) {
logger.error(jp.getSignature().getName() + "方法异常:" + e);
}
}
(4)最终增强:
xml中配置:
<aop:after method="afterLogger" point-cut-ref="pointcut"/>
package aop;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
public class AfterLogger {
private static final Logger logger = Logger.getLogger(AfterLogger.class);
public void afterLogger(JoinPoint jp) {
logger.info(jp.getSignature().getName() + "方法异常:");
}
}
(5)环绕增强:
3.注解实现IoC的配置
也就是定义Bean,然后Bean组件配装(将实体化的时候会用到的参数和参数类,进行注解表明其结构)
(1)引入命名空间,且规定注释可能出现的范围
base-package属性制定了需要扫描的基准包(多个逗号隔开)
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd"
<!-- 规定包中注解标注的类 -->
<context:component-scan base-package="service,dao">
(2)注释出Bean
这种注释方法进一步减少了配置文件的代码量
@compone("")可以注释所有类别bean
@Respository:用于标注DAO类。
@Service:用于标注业务类。
@Controller:用于标注控制器类。
下面三种特定的注释推荐使用
示例代码见(3)实现组装的例子
(3)用注释实现组装(即构造时会用到另外的Bean,需要注释)
@Autowired:Spring对此注释进行注入时,会采用按类型匹配,而不是按照方法或者bean的名字进行匹配,所以可能出现多个匹配项,所以引出下面的注释
@Qualifier(”“):可以指定所需的Bean的名称,使用时仍需要引入@Autowired
@Service("userService") //用注释来实现定义Bean
public class UserServiceImpl implements UserService{
@Autowired
private UserMapper userMapper; //这里书上例子是用的UserDao,我这里没有对UserMapper进行测试,但是道理是一样的
//这里Spring管理的时候需要用set方法进行实例化
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
/**
*当指定Bean的名字的时候
*/
@Autowired
@Qualifier("userMapper") //这里的userMapper是用(2)中注释出来的Bean名称
private UserMapper userMapper;
MyBatis与Spring的整合
一、知识了解
首先明白以下几个部分,其详细配置往下看
①SqlSessionFactoryBean
是用来代替SqlSessionFactoryBean
这里封装了使用SqlSessionFactoryBean创建SqlSessionFactroy的过程,即以配置文件形式配置SqlSessionFactroyBean来获得SqlSessionFactory实例。
②SqlSessionTemplate
(需要在PojoMapperImpl中调用进行使用)
此部分代替MyBatis中原有的SqlSession,提供数据库访问操作
自动管理会话的生命周期、关闭、提交和回滚操作。
③SqlSessionDaoSupport
(仍需要编写PojoMapperImpl类,只是不用声明SqlFactoryTempplate类,继承SqlSessionDaoSupport就行)
此部分简化了SqlSessionTemplate的配置和获取,具体过程如下:
提供了setSqlSessionFactory()来注入SqlSessionFactory实例,并创建SqlSessionTemplate实例,同时提供getSession()方法,来返回创建好的SqlSessionTemplate实例
以下是根据指定的映射器和映射文件直接生成实现类(不必写PojoMapperImpl),同时不用显示注入SqlSessionFactory了,所以②③没用了
④MapperFactoryBean
此部分以配置的方式生成映射器,并注入给业务组件(ServiceImpl中可以调用Dao层中PojoMapper接口)
自动实现PojoMapper的实现类(包括②③干的活)
缺点:如果映射器多,配置项也会多
SQL映射文件须遵循以下命名规则:
映射的命名空间和映射器接口的名称相同。映射元素的id和映射器接口的方法相同。
⑤MapperScannerConfiguer
可以扫描指定包中的接口,并将它们直接注册为MapperFactoryBean,而且会自动注入SqlSessionFactory。
【注意】映射器被注册到Spring的容器时,Spring会根据其接口名称为其命名,默认规则是首字母小写的非完全限定类名
如果使用@Autowired或者@Resource配合@Service(“pojoService”)实现对业务组件的依赖注入,可以更加简化配置文件。
二、详细配置
(建立在具有Pojo、PojoMapper、PojoMapper.xml和mybatis-config.xml还有PojoMapperImpl的基础上进行如下配置)
1.导入整合资源包
导入MyBatis-Spring 整合资源包
下载:MyBatis-Spring资源整合包中mybatis-spring-1.2.0.zip
导入:mybatis-spring-1.2.0.jar(整合)
spring-jdbc-3.2.13.RELEASE.jar (Spring的数据源支持)
spring-tx-3.2.13.RELEASE.jar (事务支持)
以下配置文件暂时放在applicationContext-mybatis.xml文件中
2.配置数据源
(1)这里使用dbcp作为数据库连接池
导入commons-dbcp-1.4.jar 和 commons-pool-1.6.jar
(2)建立applicationContext-mybatis.xml文件
<!-- 配置DataSource 以获得与数据库的连接-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url">
<!-- 这里的![CDATA[]]是用来限制字符串中出现的&等特殊字符,二义性 -->
<value><![CDATA[jdbc:mysql://localhost:3306/test_blog?characterEncoding=UTF-8]]></value>
</property>
<property name="username" value="root"/>
<property name="password" value="chiying21"/>
</bean>
3.配置SqlSessionFactoryBean
在MyBatis中,SqlSessionFactory需要用SqlSessionFactoryBuilder创建,这里可以用SqlSessionFactoryBean进行代替,它封装了SqlSessionFactoryBuilder创建SqlSessionFactory的过程,即可以通过SqlSessionFactoryBean配置获得SqlSessionFactory实例。
<!-- 配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 引用数据源组件 -->
<property name="dataSource" ref="dataSource"/>
<!-- 引用MyBatis配置文件中的配置 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 配置SQL映射文件信息 -->
<property name="mapperLocations">
<list>
<!-- 这里是指定表示扫描dao包及其任意层级子包中,任意名称的xml文件,来加载SQL映射文件 -->
<value>classpath:dao/**/*.xml</value>
</list>
</property>
</bean>
4.使用SqlSessionTemplate实现数据库操作
SqlSessionTemplate类实现了MyBatis中的SqlSession接口,可以替换原有的SqlSession实现类提供数据库访问操作。可以自动管理会话的生命周期,包括关闭、提交和回滚操作。
也就是说它主要的任务是在PojoMapperImpl中完成对数据库的连接访问传输SQL语句的功能。
而且,SqlSessionTemplate是线程安全的。!!!!!!!!!!!!!!!!!!!!
(1)配置文件:
<!-- 省略前文DataSource和sqlSessionFactory的配置 -->
<!-- 配置SqlSessionTemplate -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactroy" ref="sqlSessionFactory"/>
</bean>
<!-- 配置DAP组件并注入SqlSessionTemplate实例 -->
<bean id="userMapper" class="dao.UserMapperImpl">
<property name="sqlSession" ref="sqlSessionTemplate"></property>
</bean>
(2)使用举例:
package dao;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import Pojo.User;
public class UserMapperImpl implements UserMapper{
private SqlSessionTemplate sqlsession; //它主要的任务是在PojoMapperImpl中完成对数据库的连接访问传输SQL语句的功能。
//引入set和get方法是因为创建SqlSessionTemplate实例时,需要通过其构造方法注入SqlSessionFactroy实例,这里引用的是前面配置过的id为sqlSessionFactory的Bean
public SqlSessionTemplate getSqlsession() {
return sqlsession;
}
public void setSqlsession(SqlSessionTemplate sqlsession) {
this.sqlsession = sqlsession;
}
@Override
public int count() {
return sqlsession.selectOne("dao.user.UserMapper.count");
}
}
5.完成业务逻辑代码
这里是写UserService和UserServiceImp的部分,基本不用改变,只是UserServiceImpl中的PojoMapper需要增加get和set方法,供构造的时候使用,并注意userMapper 需要注入
<bean id="userService" class="service.UserServiceImpl">
<property name="userMapper" ref="userMapper"></property>
</bean>
6.测试类编写实例
/*
*这里只需要嗲用AppliactionContext类对象,从此对象实例化的类中用getBean方法获得已经初始化的Bean,这个ServiceBean已经获取了与数据库的链接
*/
@Test
public void testUserService() {
//在这里就已经在配置文件完成MyBatis的一系列创建,创建出来的SqlSessionTemplate可以提供给多个Dao对象使用。
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-mybatis.xml");
UserService userService = (UserService) ctx.getBean("userService");
int result = 0;
User user = new User();
user.setUsername("test_addUser");
user.setActiveCode("测试用户");
user.setEmail("example@qq.com");
user.setGender("男");
user.setIntroduce("测试用户的个人签名_一直很快乐");
user.setPassword("1");
user.setTelephone("15724594969");
result = userService.addUser(user);
}
7.用SqlSessionDapSupport类来简化SqlSessionTemplate的配置和获取。
SqlSessionDapSupport提供了setSqlSessionFactory()方法用来注入SqlSessionFactory实例并创建SqlSessionTemplate实例,同时提供了getSqlSession()方法来返回创建好的SqlSessionTemplate。
使用SqlSessionDapSupport简化了,配置文件中的SqlSessionTemplate部分,在PojoMapperImpl中也不需要定义SqlSessionTemplate和其setter方法
(1)使用方法
//在PojoMapperImpl中也不需要定义SqlSessionTemplate和其setter方法
package dao;
import java.util.List;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import Pojo.User;
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
@Override
public int count() {
return this.getSqlSession().selectOne("dao.user.UserMapper.count");
}
}
(2)配置文件
删除上部分SqlSessionTemplate
<!-- 省略数据源配置 -->
<!-- 配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 省略一些配置 -->
</bean>
<!-- 配置DAO -->
<bean id="userMapper" class="dao.UserMapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
这里也有显而易见的缺点,就是每一个pojoMapper需要手动注入sqlSessionFactory。
8.使用MapperFactoryBean注入映射器
能够以配置的方式生成映射器并注入给业务组件,就可以不用手动配置SqlSessionTemplate和SqlSessionDaoSupport来实现Dao类(可以删除PojoMapperImpl了)
配置文件
<!-- 省略数据源配置 -->
<!-- 配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 引用数据源组件 -->
<property name="dataSource" ref="dataSource"/>
<!-- 引用MyBatis配置文件中的配置 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 配置DAO -->
<!-- 这里注意calss中的属性是MapperFactoryBean -->
<bean id="userMapper" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="mapperInterface" ref="dao.UserMapper"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
9.使用MapperScannerConfigurer注入映射器
是为了简化MapperFactoryBean中配置项项(PojoMapper)很多,
MapperScannerConfigurer可以扫描指定包中的接口并将他们直接注册为MapperFactoryBean,也就是简化了上面配置DAO的部分
MapperScannerConfigurer创建所有的映射器实现都会自动被注入SqlSessionFactory实例,所以无需显示注入。(这里能够批量生成映射器实现,但是如果还使用配置文件进行一个一个的组件,还是太麻烦———就是组建userService等service需要pojomapper组件)
配置文件
<!-- 省略数据源配置 -->
<!-- 配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 引用数据源组件 -->
<property name="dataSource" ref="dataSource"/>
<!-- 引用MyBatis配置文件中的配置 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 配置DAO -->
<!-- 指定扫描范围 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" ref="dao"></property>
</bean>
①basePackage属性中可以包含多个包,用逗号分开就行
②映射器呗注册到Spring的容器时,Spring会根据其接口名称为其命名,默认规则是首字母小写的非完全限定类名。
10.使用@AutoWired或者@Resource注解实现对业务组件的依赖注入
(1)配置文件
<!-- 省略数据源配置 -->
<!-- 省略SqlSessionFactoryBean配置 -->
<!-- 配置DAO -->
<!-- 指定扫描范围 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" ref="dao"></property>
</bean>
<!-- 配置扫描注解定义的业务Bean base-package属性中执行要扫描的路径(来支持@AutoWired或者@Resource等)-->
<context:component-scan base-package="service"></context:component-scan>
(2)应用举例
@Service("userService") //用注释来实现定义Bean
public class UserServiceImpl implements UserService{
Logger logger = Logger.getLogger("rootCategory"); //获得log4j中logger的实体
@Resource //这里指定其装配参数(配合@Service("userService"))
private UserMapper userMapper;
//这里Spring管理的时候需要用set方法进行实例化
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
public UserMapper getUserMapper() {
return userMapper;
}
....
}
11.配置声明式事务(为业务层添加声明式事务)
Spring提供的声明式事务处理机制,基于AOP实现。使事务控制和事务代码与业务代码完全分离,配置即可用。
使用举例:(添加用户功能为例)
①UserMapper和User Mapper.xml文件不变(如果此方法是新增的话,因为使用MapperScannerConfigurer动态创建映射器实现,没有自定义的接口实现类,所以不需要修改相关代码)
②UserService和UserServiceImpl也不需要修改
③在配置文件中增加命名空间(都放在了applicationContext-mybatis.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
</beans>
④配置事务管理器组件——DataSourceTransactionManager
这里要注入数据源组件
<!-- 省略数据源、SqlSessionFactoryBean、DAP及其业务Bean的配置 -->
<!-- 定义事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据源组件 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
⑤通过<tx:advice >标签配置事务增强,为不同业务方法指定具体的事务规则。
标签中有以下几个属性:propagation、isolation、timeout、read-only、rollback-for、no-rollback-for
参考链接:tx:method 的属性详解
@Transactional(rollbackFor=Exception.class)的使用(这里暂时不做深入研究)
<!-- 通过<tx:advice>标签为指定的事务管理器设置事务属性,可以看出这里可以设置不同的事务管理器,而且也可以有多个<tx:advice >供下面切面使用 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- 定义属性,声明事务规则 -->
<tx:attributes >
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception.class"/>
<tx:method name="modify*" propagation="REQUIRED" rollback-for="Exception.class"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
⑥定义切面,设置上面<tx:advice >作用点
<!-- 可以看出可以针对不同的切入点,使用不同的事务增强方案 -->
<aop:config>
<!-- 定义切入点 -->
<aop:pointcut id="serviceMethod" expression="execution(* service..*.*(..))"/>
<!-- 将事务增强与切入点组合 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
</aop:config>
12.使用注解实现声明式事务处理(为业务层添加声明式事务)
即先定义事务处理,然后以注释的方式,定义事务生效的地方,而不是跟切点结合,但是暂时认为可以一起使用
(1)配置文件
<!-- 之前定义过的事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置用注释的方式配置声明事务,即定义txManager在何处生效,可以对某一方法进行额外注解设置 -->
<tx:annotation-driven transaction-manager="txManager"/>
(2)使用示例
在PojoServiceImpl.java中进行注释
@Transactional
@Service("userService") //用注释来实现定义Bean
public class UserServiceImpl implements UserService{
Logger logger = Logger.getLogger("rootCategory"); //获得log4j中logger的实体
@Resource //这里指定其装配参数(配合@Service("userService")
private UserMapper userMapper;
......
@Override
@Transactional(rollbackFor=Exception.class) //这里表示检测到异常就进行回滚
//新增用户(注册)
public int addUser(User user) {}
13.最终的配置文件(暂时都放到applicationContext-mybatis.xml中)
支持12中的注解配置事务,这里用其对特定事务进行补充
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<!-- 配置DataSource 以获得与数据库的连接-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url">
<value><![CDATA[jdbc:mysql://localhost:3306/test_blog?characterEncoding=UTF-8]]></value>
</property>
<property name="username" value="root"/>
<property name="password" value="chiying21"/>
</bean>
<!-- 配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 引用数据源组件 -->
<property name="dataSource" ref="dataSource"/>
<!-- 引用MyBatis配置文件中的配置 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 配置DAO -->
<!-- 这里使用MapperScannerConfigurer就不用显示注入SqlSessionFactory -->
<!-- 映射器被注册到Spring容器时,会根据其接口名字为其命名,默认规则是首字母小写的非完全限定类名 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="dao"></property>
</bean>
<!-- 配置扫描注解定义的业务Bean base-package属性中执行要扫描的路径(来支持@AutoWired或者@Resource等)-->
<context:component-scan base-package="service"></context:component-scan>
<!-- 下面属于事务管理部分 -->
<!-- 定义事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 通过<tx:advice>标签为指定的事务管理器设置事务属性 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- 定义属性,声明事务规则 -->
<tx:attributes >
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="modify*" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 定义切入点 -->
<aop:pointcut id="serviceMethod" expression="execution(* service..*.*(..))"/>
<!-- 将事务增强与切入点组合 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
</aop:config>
</beans>
加入SpringMVC
这里的详细优化过程,参考SSM框架的知识初步了解——MyBatis与Spring的整合,下面只写出最终配置,及其注解。
一、知识了解
要明白以下几个部分
二、详细配置
1.导入jar包
SpringMVC的包在三、spring-framewok-3.2.13.RELEASE-dist.zip中:
spring-web-3.2.13.RELEASE.jar
spring-webmvc-3.2.13.RELEASE.jar
并需要进行buildPath!!!!!!!!!!!!!!!!!!!!!
2.在web.xml中配置Servlet
web.xml在WEB-INF目录下进行新建
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<!-- 配置SpringMVC的核心控制器DispatcherServlet -->
<servlet>
<servlet-name>springMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 初始化同参数 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value> <!-- 配置文件的路径 -->
</init-param>
<!-- 这里是配置标记在程序运行时就加载此DispatcherServlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置DispatcherServlet -->
<servlet-mapping>
<servlet-name>springMvc</servlet-name> <!-- 将名为springMvc的DispatcherServlet映射到*.action,也就是会截获到jsp中名字为*.action的方法 -->
<url-pattern>/</url-pattern> <!-- 这里暂时截获并处理所有的URL请求 -->
</servlet-mapping>
<!-- 应该是设置过滤器,暂时没用到 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
3.创建SpringMVC的配置文件(springmvc-servlet.xml)
放在ersources目录下
(1)配置处理器映射(HandlerMapping)
作用就是把一个URL请求指定给一个Controller处理。
Spring提供了多种处理器映射(HandlerMapping)的支持,如:
org.springframework.web.servlert.handler.BeanNameUrlHandlerMapping
org.springframework.web.servlert.handler.SimpleUrlHandlerMapping
org.springframework.web.servlert.mvc.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlert.mvc.method.annotation.RequestMappingHandlerMapping
这里我们使用BeanNameUrlHandlerMapping(如果没有进行显示声明,Spring默认使用BeanNameUrlHandlerMapping),如:
使用配置来匹配
<!-- 声明处理器映射(HandlerMapping),如果没有声明就是默认是BeanNameUrlHandlerMapping -->
<bean name="/index.html" class="controller.IndexController"></bean> <!-- 这里用配置文件方式实现url用指定controller处理 -->
使用注释来实现(采用此方法)
<!--扫描带Controller注解的类 -->
<context:component-scan base-package="controller" />
<!-- 加载注解驱动 -->
<mvc:annotation-driven/>
(2)配置视图解析器
作用是确定指定的请求要使用哪个视图进行请求结果的输出,将控制器返回的逻辑视图名称转换成实际视图。
也有多种视图解析器,如:
org.springframework.web.servlert.view.InternalResourceViewResolver
org.springframework.web.servlert.view.ContentNegotiatingViewResolve
这里使用InternalResourceViewResolver,通过前缀后缀,最后将视图逻辑名解析成前缀/<viewName>/后缀形式的实际路径
<!-- 配置视图解析器 作用:在controller中指定页面路径的时候就不用写页面的完整路径名称了,可以直接写页面去掉扩展名的名称 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 真正的页面路径 = 前缀 + 去掉后缀名的页面名称 + 后缀 ,中间填的是返回的VIEW名-->
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
4.创建Controller(代替原来三层架构的Servlet)
在src目录下新建controller文件夹,然后这里新建indexController.java举例,
(1)第一种方法:
需要继承org.springframework.web.servlet.mvc.AbstractControlle,并实现handleRequest Internal方法
配置文件
<!-- 声明处理器映射(HandlerMapping),如果没有声明就是默认是BeanNameUrlHandlerMapping -->
<bean name="/index.html" class="controller.IndexController"></bean> <!-- 这里用配置文件方式实现url用指定controller处理 -->
Controller的JavaBean
package controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
public class IndexController extends AbstractController{
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
System.out.println("~~~~~~~~~~IndexController~~~~~~~~~~~~");
return new ModelAndView("index"); //这里就对应上面3.(2)中说的逻辑视图名(viewName),也就是说在这里去访问index.jsp文件
}
}
(2)第二种方法:
使用@Controller对Controller类进行标注,使其成为一个可处理HTTP请求的控制器,再使用@RequestMapping对Controller中的方法进行标注,确定方法对应的URL。(注意@Request Mapping可以嵌套,见书P234示例8)
配置文件
<!--扫描带Controller注解的类 -->
<context:component-scan base-package="controller" />
<!-- 加载注解驱动 -->
<mvc:annotation-driven/>
Controller的JavaBean
package controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
@Controller //
public class IndexController{
private Logger logger = Logger.getLogger("rootCategory"); //获得log4j中logger的实体
@RequestMapping("/index")//
public String index() {
System.out.println("~~~~~~~~~~~~@RequestMapping(\"index\")~~~~~~~~~~~~~~~");
logger.info("~~~~~~~~~~~~@RequestMapping(\"index\")~~~~~~~~~~~~~~~");
return "index";
}
}
最终spring-servlet.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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 扫描带Controller注解的类 -->
<!-- <context:component-scan base-package="controller" /> -->
<!-- 加载注解驱动 -->
<!-- <mvc:annotation-driven/> -->
<!-- 声明处理器映射(HandlerMapping),如果没有声明就是默认是BeanNameUrlHandlerMapping -->
<bean name="/index.html" class="controller.IndexController"></bean> <!-- 这里用配置文件方式实现url用指定controller处理 -->
<!-- 配置视图解析器 作用:在controller中指定页面路径的时候就不用写页面的完整路径名称了,可以直接写页面去掉扩展名的名称 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 真正的页面路径 = 前缀 + 去掉后缀名的页面名称 + 后缀 ,中间填的是返回的VIEW名-->
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
5.创建View(这里是jsp文件)
6.参数传递部分(书P232)
View to Controller
(1)@RequestMapping来传递参数
但是这个有弊端,是如果在方法中已经定义一个参数了,但是实际并没有传过来的话就会报400错误,同样url传的参数名和这里定义接受的参数名不一样的话,也会同样找不到,然后报400错误。
在Controller中写
//此函数
@RequestMapping(value="/test",method = RequestMethod.GET,params = "username")
public String test(@RequestParam String username) {
System.out.println("~~~~~~~~~~~~@RequestMapping(\"/test\")~~~~~~~~~~~~~~~");
logger.info("~~~~~~~~~~~~@RequestMapping(\"/test\")~~~~~~~~~~~~~~~");
logger.info("test,username:" + username);
return "test";
}
测试方法: http://localhost:8080/test_ssm_Spring_MyBatis_Spring_SpringMVC/test?username=ddz
(2)@RequestParam来注解指定参数
解决上面的参数问题,会设定参数是否必要,使用@RequestParam来注释实现
@RequestMapping("/test2")
public String test2(@RequestParam(value = "username",required = false) String username) {
System.out.println("~~~~~~~~~~~~@RequestMapping(\"/test2\")~~~~~~~~~~~~~~~");
logger.info("~~~~~~~~~~~~@RequestMapping(\"/test2\")~~~~~~~~~~~~~~~");
logger.info("test2,username:" + username);
return "test";
}
Controller to View
(1)ModelAndView
①添加模型数据:
ModelAndView addObject(String attributeName,Object attributeValue):该方法的第一个参数为key值,第二参数为key对应的value。key需要保证在该Model的作用域内唯一即可。
ModelAndView addAllObjects(Map<String,?> modelMap):可以添加Map对象到Model中。
②设置视图:
void setView(View view):指定一个具体的视图(也就是说相对应于根目录的路径)
void setViewName(String viewName):指定一个逻辑视图,通过视图解析器,得到路径
@RequestMapping("/test_ModelAndView")
public ModelAndView test_ModelAndView(@RequestParam(value = "username",required = false) String username,@RequestParam(value = "password",required = false) String password) {
System.out.println("~~~~~~~~~~~~@RequestMapping(\"/test_ModelAndView\")~~~~~~~~~~~~~~~");
logger.info("~~~~~~~~~~~~@RequestMapping(\"/test_ModelAndView\")~~~~~~~~~~~~~~~");
ModelAndView mView = new ModelAndView();
logger.info("test_ModelAndView,username:" + username);
logger.info("test_ModelAndView,username:" + password);
mView.addObject("username2",username); //这里第一个参数是key,第二个参数是value。即在mView中添加一对KV
mView.addObject("password2",password);
mView.setViewName("test"); //这里给mView指定一个逻辑视图名,在return后通过视图解析器,能够去访问test.jsp文件(带着上面两个参数)
return mView;
}
(2)Model
这里比较ModelAndView而言好像没什么优势,addAttribute和上面的addObject一样,还能放入javaBean(如Pojo.user),jsp中用下面代码来接收。
<div>user.username:  ${user.username}</div>
@RequestMapping("/test_Model")
//在参数中添加Model,用addAttribute方法添加KV,就可以了,SpringMVC负责将Model传动给前端
public String test_Model(@RequestParam(value = "username",required = false) String username,@RequestParam(value = "password",required = false) String password,Model model) {
System.out.println("~~~~~~~~~~~~@RequestMapping(\"/test_Model\")~~~~~~~~~~~~~~~");
logger.info("~~~~~~~~~~~~@RequestMapping(\"/test_Model\")~~~~~~~~~~~~~~~");
logger.info("test_Model,username:" + username);
logger.info("test_Model,password:" + password);
User user = new User();
user.setUsername("user.username");
// user = userService.getUserByUsernameAndPassword(username, password);
model.addAttribute("username2",username); //这里第一个参数是key,第二个参数是value。即在mView中添加一对KV
model.addAttribute("password2",password);
model.addAttribute("user",user);
return "test";
}
(3)Map
和上面Model一样,因为它本身就是一个Map形式的数据结构,所以在上面代码中做出如下修改,然后参数放入的方法使用map的方法put就可以了
public String test_Model(@RequestParam(value = "username",required = false) String username,@RequestParam(value = "password",required = false) String password,Map<String,Object> model) {
.....
model.put("user",user);
.....
}