发表于: 2018-03-14 23:03:59

1 548


今日完成

日报回复:

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);

依赖注入主要有两种方法

1setter注入

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。



返回列表 返回列表
评论

    分享到