Java学习日记-SSM框架学习

479 阅读2分钟

SSM

Mybatis+Spring

Mybatis教程

Spring框架总结

SSM整合1

SSM整合2

Mybatis整体架构:

创建步骤:

引入依赖(pom.xml)

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
</dependency>
 <!--数据库驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.6</version>
</dependency>
<!--三大连接池了解一下,选一个用,了解连接池的作用-->
<!--德鲁伊,来自于阿里的数据源(连接池)-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.12</version>
</dependency>

全局配置文件(application.xml)

<!--配置一个数据源(连接池)-->
    <!--引入的是德鲁伊连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <!-- ?characterEncoding=utf-8 为了解决数据进数据库后中文乱码的问题-->
        <property name="url" value="jdbc:mysql:///myssm?characterEncoding=utf-8">				</property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>

        <property name="maxActive" value="20"/>
        <property name="initialSize" value="1"/>
        <property name="minIdle" value="1"/>
    </bean>
<!--配了连接池给谁用呢?数据库用,怎么用?通过Mybatis的org.mybatis.spring.SqlSessionFactoryBean包在sql会话工厂里用,这个工厂用来干嘛的?用来操作数据库,怎么操作数据库?用sql语句操作,sql语句在哪里?Mapper.xml里-->

乱码问题1--解决数据库乱码:

?characterEncoding=utf-8 为了解决数据进数据库后中文乱码的问题

写dao接口

public interface UserDao {
    public int add(User User);
//    根据id删除,为什么要传入一个对象?
    public int delete(int id);
    public int update(User User);
    public User get(int id);
    public List<User> getAll();
}

几个相关的问题:

  1. Dao类为什么是接口?

    • 为了后期的维护,假如修改了dao中的代码,只要编译dao中的代码,不用管servlet,因为servlet就像引用一样,dao长什么样它就怎么用;
    • 为什么要用Service接口?是让表示层不依赖于业务层的具体实现。为什么要用DAO接口?是让业务层不依赖于持久层的具体实现。有了这两个接口,Spring IOC容器才能发挥作用。
  2. 根据id删除,为什么要传入一个对象?

    • 为了方便后期维护?不想按id修改时可以按其他数据修改
  3. model类为什么要实现Serializable这个接口?

    • 为了JavaBean可以实现对象序列化,而实现java.io.Serializable 接口的类是可序列化的。没有实现此接口的类将不能使它们的任一状态被序列化或逆序列化。

    • 对象序列化就是可以把对象存到字节流,然后可以恢复!当一个JavaBean在构造工具内被用户化,并与其它Bean建立连接之后,它的所有状态都应当可被保存,下一次被load进构造工具内或在运行时,就应当是上一次修改完的信息。为了能做到这一点,要把Bean的某些字段的信息保存下来,在定义Bean时要使它实现Java.io.Serializable接口。

    • 对象序列化后用在哪里了?

配置Mapper.xml

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:命名空间,随便写,一般保证命名空间唯一-->
<mapper namespace="com.wangym.dao.UserDao">
    <!--写增删改查,sql语句不要';'-->
    <insert id="add" parameterType="User">
        <!--最好不要有注释,可能会报错  #{}和${}的区别-->
        <!-- #{}和${}的区别? -->
        <select id="get" parameterType="int" resultType="User">
       		 select * FROM `users` where id=#{id}
    	</select>
    </insert>
</mapper>

如何预防sql注入的问题:#{}和${}的区别?

  • #{}是预编译处理,${}是字符替换,mybatis在处理#{}时会将sql中的#{}替换为?,调用preparedStatement通过set方法按占位符"?"先后顺序来赋值;将${}替换为里面的值
  • SQL 语句被预编译并且存储在 PreparedStatement 对象中。然后只需要生成一个执行计划,就可以使用此对象高效多次执行该语句。

CRUD里的属性

<select
id="get"        statement的id或者叫sql的id  个人理解=方法名
parameterType="int"  声明输入参数的类型              参数类型
resultType="User"    声明输入结果的类型全路径       结果集的封装类型
>

在mybatisCnfig.xml中添加配置

  1. 得到sqlSessionFactory,打开数据源(连接池dataSource),挂接映射文件(mapper.xml)

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <!--挂接映射文件-->
        <property name="mapperLocations" value="classpath:mapper/*.xml"/> 
    	<!--设置别名,在Mapper文件里面就可以直接写对应的类名,而不用写全路径名了-->   
        <property name="typeAliasesPackage" value="com.wangym.model"/>
    </bean>
    
    • property标签的name属性是指bean标签中class属性的类中的私有属性名,

      如果该属性的值是引用的其它bean,那么就不能用value标签,而是ref标签

      如果该属性的值引用了匿名内部类,则直接使用bean标签即可(不指定id或name属性)

    • ref作为属性时,就是查找当前配置文件的bean,作为标签时就是寻找全局中的 bean

写service实现dao

  1. dao类是接口,Service implements Dao就要@Override dao的方法,显然没有比在dao里直接写简便,所以要实现dao接口不用implements,而是用注解

  2. 其实dao的实现类,就是dao的bean是通过扫描组建生成的

     <!--dao的扫描器,生成dao的实现类-->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <!--配的是所有dao接口所在包名-->
            <property name="basePackage" value="com.wangym.dao"/>
        </bean>
    
  3. @Service
    public class UserService implements UserDao {
        @Resource    
        private UserDao userDao;
    }
    
    1. 注解@Service是什么意思,有什么作用

      • 如果一个类带了@Service注解,将自动注册到Spring容器,不需要再在applicationContext.xml配置文件中定义bean了,类似的还包括@Component、@Repository、@Controller
    2. 注解@Resource与@Autowired的区别

      • 注入方式不同:

        ​ @Resource先按名字不行再按类型注入,

        ​ @Autowired只能按类型注入,要按名称就得结合@Qualifier注解一起使用

      • 提供方不同:前者是J2EE提供,后者是spring提供

  4. 在applicationContext.xml配置文件中打开组件扫描配置

    <context:component-scan base-package="com.wangym"/>
    

写UserDao的测试类

  1. 在src文件夹下新建test.java.com.wangym.service.UserDaoTest

写控制器类

写前端页面

运行报错:

  1. java.lang.IllegalStateException: Failed to load ApplicationContext

    详细:Error creating bean with name XXX: Injection of resource dependencies failed

    原因:web.xml没有配置spring的上下文环境和核心的监听器

    解决方法:

  2. javax.servlet.ServletException: Servlet.init() for servlet [springmvc] threw exception

    BeanCreationException: Error creating bean with name 'userController': Injection of resource dependencies failed;

    详细:Servlet.init()初始化错误,错误一般发生在控制器中,当出现重名的servlet时候也会报类似的错误

    原因:controller中出现了,不存在的控制器引用

    例如:return “redirect:/admin/query.action”,返回重定向到另外一个控制器,但是控制器未定义,就会出现上述错误!

applicationContext.xml配置超详细

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p">

<!-- 配置组件包扫描的位置 -->
<context:component-scan base-package="cn.sxt" />
<!-- 读取db.properties配置文件到Spring容器中 -->
<context:property-placeholder
    location="classpath:db.properties" />
    
<!-- 配置 阿里巴巴的 druid 数据源(连接池) -->
<bean id="dataSource"
    class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
    destroy-method="close">
    <!-- SpringEL 语法 ${key} -->
    <property name="driverClassName"
        value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />

    <!-- ${username}如果key是username,name 默认spring框架调用的当前操作系统的账号 解决方案:可以统一给key加一个前缀 -->

    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <property name="maxActive" value="${jdbc.maxActive}" />

</bean>
<!-- 创建SqlSessionFactory MyBatis会话工厂对象 -->
<bean id="sqlSessionFactory"
    class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 注入数据源 -->
    <property name="dataSource" ref="dataSource" />
    <!-- 读取映射文件 ,MyBatis的纯注解不用配置 -->
    <property name="mapperLocations">
        <array>
            <!-- 配置单个映射文件 -->
            <!-- <value>classpath:cn/zj/ssm/mapper/UserMapper.xml</value> -->
            <!-- 配置多个映射文件使用 * 通配符 -->
            <value>classpath:cn/sxt/mapper/*Mapper.xml</value>
        </array>

    </property>
    <!-- 配置mybatis-confg.xml主配置文件(注配置文件可以保留一些个性化配置,缓存,日志,插件) -->
    <property name="configLocation"
        value="classpath:mybatis-config.xml" />
    <!-- 配置别名,使用包扫描 -->
    <property name="typeAliasesPackage" value="cn.sxt.pojo"></property>
</bean>
<!-- SqlSession 不用单独创建,每次做crud操作都需要Mapper接口的代理对象 而代理对象的创建又必须有 SqlSession对象创建 
    Spring在通过MyBatis创建 Mapper接口代理对象的时候,底层自动把SqlSession会话对象创建出来 -->

<!-- 创建UserMapper接口的代理对象,创建单个代理对象 参考桥梁包:org.mybatis.spring.mapper.MapperFactoryBean<T> 
    此类就是创建 Mapper 代理对象的类 -->
<!--<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> 
    注入UserMapper接口 <property name="mapperInterface" value="cn.sxt.mapper.UserMapper"/> 
    注入sqlSessionFactory工厂对象 <property name="sqlSessionFactory" ref="sqlSessionFactory"/> 
    </bean> -->
<!-- 使用包扫描创建代理对象,包下面所有Mapper接口统一创建代理对象 使用桥梁包下面 : org.mybatis.spring.mapper.MapperScannerConfigurer 
    可以包扫描创建所有映射接口的代理对象 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- 配置SqlSessionFactoryBean的名称 -->
    <property name="basePackage" value="cn.sxt.mapper"/>
    <!-- 可选,如果不写,Spring启动时候。容器中。自动会按照类型去把SqlSessionFactory对象注入进来 -->
    <!-- <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> -->

    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>

</bean>
<!--  1.配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据源 -->

<property name="dataSource" ref="dataSource"></property>

</bean>
<!-- 
    2.配置事务的细节
    配置事务通知/增强
 -->
 <tx:advice id="tx" transaction-manager="transactionManager" >
 
 <!-- 配置属性 -->
     <tx:attributes>
         <!-- DQL  -->
         <tx:method name="select*" read-only="true" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="5"/>
         <tx:method name="query*" read-only="true" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="5"/>
         <tx:method name="get*" read-only="true" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="5"/>
         <tx:method name="find*" read-only="true" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="5"/>
         <!-- 其他 -->
         <tx:method name="*" read-only="false" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="5"/>
 </tx:attributes>
 </tx:advice>

<!-- 
        3.使用AOP将事务切到Service层
    -->
    <aop:config>
        <!-- 配置切入点 -->
        <aop:pointcut expression="execution(* cn.zj.ssm.service..*.*(..))" id="pt"/>
    <!-- 配置切面= 切入点+通知 -->
    <aop:advisor advice-ref="tx" pointcut-ref="pt"/>
    </aop:config>
</beans>