发表于: 2018-03-14 23:03:59
1 547
今日完成
日报回复:
Spring的控制反转是如何实现的?
所谓的依赖就是对象之间的一种关系,比如a对象依赖于b对象,那么a类中就会有b类的引用(简单理解就是拥有b类的这么一个属性),也就是说a对象要想执行一个完整的功能,必须建立一个前提——a对象中的b类属性已经实例话,并且拥有b类的一切功能;现在可以去了解什么是依赖注入了,就像前面说过的,a对象想完成一个完整的功能,要先为自己的b类属性实例化,而在MVC模式中,这种现象很常见,为了简化这种实例化的工作,spring容器就产生了,它可以统一管理这种实例化频繁的操作,就是说这种本来应由自己实例化的工作交给Spring容器去控制了,也就是控制反转了,实现的方案之一是在上述a类中提供一个关于b类的setter方法,这个方法会被Spring容器控制。
举例:控制反转的体现,把对象实例化交给Spring去控制,程序员并不用管
配置文件如下:
<bean id="person" class="com.wyq.Spring.Person">
<property name="age" value="12" />
<property name="name" value="Tom"/>
接下来,要使用这个bean的时候,只需下面的这个方法:
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
Person person=ctx.getBean("Person",Person.class);
依赖注入主要有两种方法
1)setter注入
setter注入是在bean实例创建完毕之后执行。
在Java中有个约定(Convention),那就是属性的设置和获取的方法名一般是:set+属性名(参数)及get+属性名()的方式。
示例:
public class MessageHandler {
private MessageService messageService;
public MessageService getMessageService() {
return messageService;
}
public void setMessageService(MessageService messageService) {
this.messageService = messageService;
}
public String handle() {
return messageService.sendService();
}
}
使用Setter方法注入如下所示
<bean id="messageService"class="huangbowen.net.DependecyInjection.ConstructorInjection.SimpleMessageService"/>
<bean id="messageHandler" class="huangbowen.net.DependecyInjection.SetterInjection.MessageHandler">
<property name="messageService" ref="messageService"/>
</bean>
如果property的name为messageService,那么必须在类中有个叫做setMessageService的方法,这样才能完成注入。如果将MessageHandler.java中的setMessageService方法改为setMessageService1,那么注入就会失败,失败message如下所示。
java.lang.IllegalStateException: Failed to load ApplicationContext
2)构造注入
今天请教了师兄项目结构:
现在的编程方式标准主流都是采用MVC综合设计模式,MVC本身不属于设计模式的一种,它描述的是一种结构,最终目的达到解耦,解耦说的意思是你更改某一层代码,不会影响其他层代码。
1,modle层:实体层 数据库在项目中的类。
2,Dao层: 持久层,主要与数据库进行交互
DAO层首先会创建DAO接口,然后会在配置文件中定义该接口的实现类,接着就可以在模块中就可以调用DAO 的接口进行数据业务的而处理,并且不用关注此接口的具体实现类是哪一个类。DAO 层的数据源和数据库连接的参数数都是在配置文件中进行配置的。
3,Service层:业务层 做相应的业务逻辑处理
Service层主要负责业务模块的逻辑应用设计。和DAO层一样都是先设计接口,再创建要实现的类,然后在配置文件中进行配置其实现的关联。接下来就可以在service层调用接口进行业务逻辑应用的处理。封装Service层的业务逻辑有利于业务逻辑的独立性和重复利用性。
4,Controller层:(action层) 控制层 控制业务逻辑
Controller层负责具体的业务模块流程的控制,controller层主要调用Service层里面的接口控制具体的业务流程,控制的配置也需要在配置文件中进行。
5、View层 此层与控制层结合比较紧密,需要二者结合起来协同工发。View层主要负责前台jsp页面的表示,
Conroller层和Service层的区别是:Controlle层负责具体的业务模块流程的控制;Service层负责业务模块的逻辑应用设计;
总结:在具体的项目中,其流程为:Controller层调用Service层的方法,Service层调用Dao层中的方法,其中调用的参数是使用Model层进行传递的。
Spring扫描组件使用详解
如果不想在xml文件中配置bean,我们可以给我们的类加上spring组件注解,只需再配置下spring的扫描器就可以实现bean的自动载入。
<!-- 注解注入 -->
<context:component-scan base-package="com.b505.common.service.impl" />
需要注意的是:
在base-package指明一个包:
<context:component-scan base-package="com.b505"/>
表明com.b505包及其子包中,如果某个类的头上带有特定的注解
@Component,@Repository,@Service,@Controller,就会将这个对象作为Bean注入进spring容器。
Spring常用注解
《在持久层、业务层和控制层分别采用 @Repository、@Service 和 @Controller 对分层中的类进行注释,而用 @Component 对那些比较中立的类进行注释》
1,使用@Controller注解标识UserController之后,就表示要把UserController交给Spring容器管理,在Spring容器中会存在一个名字为“userController”的action,这个名字是根据UserController类名字取的。注意:如果@Controller不指定其value,则默认的bean名字为这个类的类名首字母小写,如果指定value[@Controller(value="UserController")]或者[@Controller("UserAction")],则使用value作为bean的名字。
@Controller后还可以使用@Scope注解,如@Scope(“prototype”)表示将Action的范围声明为原型,可以利用容器scope=“prototype”来保证每一个请求都有一个单独的Action来处理,避免struts中的Action的线程安全问题。spring默认scope是单例模式(scope=“singleton”).这样只会创建一个Action对象,每次访问都是同一个Action对象,数据不安全,struts2是要求每次访问都对应不同的Action,scope="prototype"可以保证当有请求的时候都创建一个Action对象。
2,@Service对应的是业务层Bean,例如:
@Service("userService")
public class UserServiceImpl implements IUserService {
@Resource
private UserDao userDao; }
@Service("userService")注解是告诉Spring,当Spring要创建UserServiceImpl的实例时,bean的名字必须叫做“userService”,这样当Action需要使用UserServiceImpl的实例时,就可以由Spring创建好的“userService”然后注入给Action:在Action只需要声明一个名字叫“userService”的变量来接收由Spring注入的“userService”即可,具体代码如下:
@Controller
@RequestMapping("/user")
public class UserController {
@Resource
private IUserService userService; }
注意,在Action声明的“userService”变量的类型必须是"UserServiceImpl"或者其父类“IUserService”,否则由于类型不一致而无法注入,由于Action中的声明“userService”使用了变量@Resource注解去标注,当Spring看到userService变量上的@Resource的注解时就可以知道Action需要用到一个UserServiceImpl的实例,此时Spring就会把自己创建好的名字叫做“userService”的UserServiceImpl的实例注入给Action中的“userService”变量,帮助Action完成userService的实例化。
这样在Action中就不用通过“UserService userService = new UserServiceImpl();”这种最原始的方式去实例化userService了。创建UserServiceImpl实例的任务交给Spring来做,Spring把创建好的UserServiceImpl实例交给Action,Action拿到就可以直接用。
3,@Respository对应数据库访问层Bean,例如
@Repository
public interface UserDao {
// @Select("select * from user_t where id=#{userId}")
public User selectByPrimaryKey(int userId);
@Repository注解告诉Spring,让Spring创建一个名字叫做”userDao”的UserDao实例,当Service需要使用Spring创建的名字叫做“userDao”的UserDao实例时,就可以使用@Resource注解告诉Spring,Spring把创建好的userDao注入给Service即可:
@Service("userService")
public class UserServiceImpl implements IUserService {
@Resource
private UserDao userDao;
public User getUserById(int userId) {
return this.userDao.selectByPrimaryKey(userId);
}
}
用mybatis实现CRUD
映射文件如下:
<mapper namespace="com.ycc.mapping.userMapper">
<select id="getUser" parameterType="int" resultType="com.ycc.model.User">
select * from users where id=#{id}
</select>
<insert id="addUser" parameterType="com.ycc.model.User">
insert into users(name,age) values(#{name},#{age})
</insert>
<delete id="deleteUser" parameterType="int">
delete from users where id=#{id}
</delete>
<update id="updateUser" parameterType="com.ycc.model.User">
update users set name=#{name},age=#{age} where id=#{id}
</update>
<select id="getAllUsers" resultType="com.ycc.model.User">
select * from users
</select>
</mapper>
然后写了一个工具类,将如下几个需要重复的步骤封装在里面,以免每次用的时候都去写
1,使用类加载器加载mybatis的配置文件
InputStream is = Test1.class.getClassLoader().getResourceAsStream(resource);
(也可以使用MyBatis提供的Resources类加载mybatis的配置文件Reader reader = Resources.getResourceAsReader(resource);)
2,构建sqlSession的工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
3,创建能执行映射文件中sql的sqlSession
SqlSession session = sessionFactory.openSession();
public static SqlSessionFactory getSqlSessionFactory() {
String resource= "config.xml";
InputStream is = MyBatisUtil.class.getClassLoader().getResourceAsStream(resource);
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
return factory;
}
public static SqlSession getSqlSession() {
return getSqlSessionFactory().openSession();
}
public static SqlSession getSqlSession(boolean isAutoCommit) {
return getSqlSessionFactory().openSession(isAutoCommit);
}
}
测试类
增加
@Test
public void testAdd() {
SqlSession sqlSession = MyBatisUtil.getSqlSession(true);
String statement = "com.ycc.mapping.userMapper.addUser";
User user=new User();
user.setName("德法俄武器");
user.setAge(23);
int retResult = sqlSession.insert(statement, user);
sqlSession.close();
System.out.println(retResult);
}
更新
@Test
public void testUpdate() {
SqlSession sqlSession = MyBatisUtil.getSqlSession(true);
String statement = "com.ycc.mapping.userMapper.updateUser";
User user = new User();
user.setId(6);
user.setName("健康领域");
user.setAge(24);
int retResult = sqlSession.update(statement, user);
sqlSession.close();
System.out.println(retResult);
}
删除
@Test
public void testDelete() throws Exception {
SqlSession sqlSession = MyBatisUtil.getSqlSession(true);
String statement = "com.ycc.mapping.userMapper.deleteUser";
User user = new User();
user.setId(4);
int retResult = sqlSession.delete(statement, user);
sqlSession.close();
System.out.println(retResult);
}
查询所有
@Test
public void testGetAllUsers() throws Exception {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
String statement = "com.ycc.mapping.userMapper.getAllUsers";
//执行查询操作,将查询结果自动封装成List<User>返回
List<User> listUsers = sqlSession.selectList(statement);
sqlSession.close();
System.out.println(listUsers);
}
遇到的疑惑
查询的时候报了异常:A query was run and no Result Maps were found for the Mapped Statement
原因:使用mybatis进行查询时,没有给定resultType值出现的错误。resultType是查询对象的类型。
解决:
<select id="getAllUsers" parameterType="com.ycc.model.User">
select * from users
</select>
将parameterType改为resultType
然后就去查了一下mybatis映射文件的标签
MyBatis映射文件常用标签
1.<select>:用于编写查询语句用的标签
id:表示当前<select>标签的唯一标识
parameterType:指定查询限制条件的输入类型,一般使用#{}实现的是向prepareStatement中的预处理语句中设置参数值
resultType:指定查询返回结果的输出类型,如果返回的结果是一个实体类,必须要求实体类的属性和表的字段名称相同
resultMap:也是一个输出类型,配合<resultMap>标签使用
flushCache:设置查询的时候是否清空缓存,默认为false
useCache:将查询结果放入缓存中,默认为true
timeout:设置查询返回结果的最大响应时间
fetchSize:每次批量返回的结果行数。默认不设置
statementType:STATEMENT、PREPARED或CALLABLE的一种,这会让MyBatis使用选择Statement、PreparedStatement或CallableStatement。默认值:PREPARED
resultSetType:设置游标FORWARD_ONLY、SCROLL_SENSITIVE、SCROLL_INSENSITIVE中的一种。认不设置
2.<resultMap>:用于解决实体类中属性和表字段名不相同的问题
id:表示当前<resultMap>标签的唯一标识
result:定义表字段和实体类属性的对应关系
property:记录实体类的属性
column:记录表的字段名称
3.<mapper>:每个映射文件的根标签,重点关注<mapper>标签中namespace属性
4.<sql>:可以重用的SQL语句,可以被其他语句引用
<sql id="userColumns">id,username,password</sql>
<select id="selectUsers" paramertType="int" resultType="hashmap">
select <include refid="userColumns"/>
from some_table
</select>
5.<insert>:用于编写插入语句用的标签
<insert id=”addMyUser” parameterType=”com.gxa.pojo.MyUser”>
insert into MyUser (username, userpass) values (#{username}, #{userpass})
</insert>
6.<update>:用于编写更新语句用的标签
<update id=”updateMyUser” parameterType=”com.gxa.pojo.MyUser”>
Update MyUser set username=#{userName} where userId=#{userId}
</update>
7.<delete>:用于编写删除语句用的标签
<delete id=”delMyUser” parameterType=”java.lang.Integer”>
delete from myuser where userId = #{id}
</delete>
8.<cache>:配置给定命名空间缓存
9.<cache-ref>:从其他命名空间引用缓存配置
10.MyBatis中用于实现动态SQL的元素主要有
- <if>
- <choose>(when,otherwise)
- <trim>
- <where>
- <set>
- <foreach>
明日计划
继续学习spring和mybatis
收获
学习了一些基础知识,还有师兄给讲了下项目结构规范,以及mybatis的CRUD。
评论