spring

spring配置

bean创建

创建一个bean接口

java 复制代码
package com.itheima.dao;

public interface UserDao {
    public void save();
}

实例化bean

java 复制代码
package com.itheima.dao.impl;

import com.itheima.dao.UserDao;

public class UserDaoImpl implements UserDao {
    public void save() {
        System.out.println("save running...");
    }

    public void init() {
        System.out.println("save running...");
    }
    public void destory() {
        System.out.println("save running...");
    }
}

在resource下创建配置文件加载bean

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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" scope="singleton" init-method="init" destroy-method="destory">
        <!-- 默认情况下是调用无参构造-->
        <!--scope:指对象的作用范围,取值如下
            singleton: 默认值,单例的,此时当应用加载spring的核心文件时,实例化配置的bean实例,只要容器在,对象就一直存在,容器销毁时对象一起销毁
            prototype: 多例的,在调用getbean时创建实例,当对象长时间不使用时,被java的垃圾回收器回收
            request:web项目中,spring创建一个Bean的对象,将对象存入到request域中
            session:web项目中,spring创建一个Bean的对象,将对象存入到session域中
            global session:web项目中,应用在Portlet环境,如果没有应用在Portlet环境那么global session相当于session
         -->
        <!-- init-method
            用于指定init方法
            init方法用于初始化
        -->
        <!-- destroy-method
            用于指定destory方法
            destory方法用于对象销毁时做一系列事情
        -->
    </bean>

    <!-- bean 的三种实例化方法
          1. 无参构造
          2. 工厂的静态方法实例化方法
          3. 工厂实例方法实例化
      -->
    <!-- 工厂静态方法实例化方法, 找到com.itheima.factory.staticFactory工厂内的getUserDao方法返回的对象  getUserDao是静态方法 -->
    <bean id="userDao" class="com.itheima.factory.staticFactory" factory-method="getUserDao"></bean>

    <!-- 工厂实例方法实例化 -->
    <!-- 先创建工厂 -->
    <bean id="factory" class="com.itheima.factory.DynamicFactory"></bean>
    <!-- 创建factory工厂的getUserDao方法返回的对象 -->
    <bean id="userDao" factory-bean="factory" factory-method="getUserDao"></bean>
</beans>

工厂的静态方法实例化方法需要创建工厂

java 复制代码
package com.itheima.factory;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;

public class staticFactory {
    public static UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

工厂实例方法实例化需要创建工厂

java 复制代码
package com.itheima.factory;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;

public class DynamicFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

依赖注入

在编写程序时,通过反转控制,把对象的创建交给spring,但是代码中不可能出现没有依赖的情况。IOC解耦知识降低他们的依赖关系,但是不会消除

将业务层和持久层的依赖关系,在使用spring之后,让spring来维护

bean的依赖注入方法:

  1. 构造方法
  2. set方法
    将UserDao注入UserService,程序获得UserService实例,内部已经存在UserDao实例了,直接调用UserDao的save方法即可

set方法注入bean

模拟web层

java 复制代码
public class UserDaoDemo {
    public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) app.getBean("userService");
        userService.save();
    }
}

修改service层

通过依赖注入的方法后,service可以直接使用bean对象,不需要单独创建

java 复制代码
package com.itheima.service.impl;

import com.itheima.dao.UserDao;
import com.itheima.service.UserService;

public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void save() {
    	// 直接使用userDao
        userDao.save();
    }
}

依赖文件

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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" ></bean>
    
    <bean id="userService" class="com.itheima.service.impl.UserServiceImpl" >
    <!--
        ref="userDao"  指的是容器中的userDao
        name="userDao" 指的是userService中的userDao属性
        将容器中的userDao通过setUserDao方法注入userService中
    -->
        <property name="userDao" ref="userDao"></property>
    </bean>
</beans>

p命名空间的方法注入

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!--
    p命名空间引入
    复制第一行xmlns="http://www.springframework.org/schema/beans"
    加上:p
    将最后的beans改成p
    最终成为xmlns:p="http://www.springframework.org/schema/p"
-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" ></bean>
    <!-- 通过p命名空间的方式注入
        p:userDao="userDao" 注入普通属性
        p:userDao-ref="userDao" 注入对象属性
    -->
    <bean id="userService" class="com.itheima.service.impl.UserServiceImpl" p:userDao-ref="userDao"></bean>
</beans>

使用构造方法的方式注入bean

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" ></bean>
    <bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
    <!--
        name="userDao" 构造方法的参数名
        ref="userDao"  引用容器中的名字
    -->
        <constructor-arg name="userDao" ref="userDao"></constructor-arg>
    </bean>
</beans>

普通属性的注入

修改bean

java 复制代码
package com.itheima.dao.impl;

import com.itheima.dao.UserDao;

public class UserDaoImpl implements UserDao {

    private String username;
    private int age;

    public void setUsername(String username) {
        this.username = username;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void save() {
        System.out.println("save running...");
    }

}

属性注入

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" >
        <!--
            向bean中注入普通属性
        -->
        <property name="username" value="zhangsan"/>
        <property name="age" value="18"/>
    </bean>
</beans>

集合注入

创建user

java 复制代码
package com.itheima.demo;

public class User {
    private String username;
    private int age;

    public void setUsername(String username) {
        this.username = username;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

修改UserDao

java 复制代码
package com.itheima.dao.impl;

import com.itheima.dao.UserDao;
import com.itheima.demo.User;

import java.util.List;
import java.util.Map;

public class UserDaoImpl implements UserDao {

    private List<String> strList;
    private Map<String, User> user;

    public void setUser(Map<String, User> user) {
        this.user = user;
    }

    public void setStrList(List<String> strList) {
        this.strList = strList;
    }


    @Override
    public void save() {
        System.out.println(strList);
        System.out.println(user);
        System.out.println("save...");
    }
}

向UserDao注入集合

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
        注入user对象,要注入User的map集合,要先注入user
    -->
    <bean id="user1" class="com.itheima.demo.User">
        <property name="username" value="zhangsan"/>
        <property name="age" value="18"/>
    </bean>

    <bean id="user2" class="com.itheima.demo.User">
        <property name="username" value="lisi"/>
        <property name="age" value="24"/>
    </bean>

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" >
        <!--
        注入普通的列表集合
    -->
        <property name="strList">
            <list>
                <value>"zhangsan"</value>
                <value>"lisi"</value>
            </list>
        </property>
        <!--
            注入bean的的map集合
        -->
        <property name="user">
            <map>
                <entry key="zhangsan" value-ref="user1"></entry>
                <entry key="lisi" value-ref="user2"></entry>
            </map>
        </property>
    </bean>
</beans>

分文件开发

先创建一个applicationContext-dao.xml配置文件

在主配置文件中加载applicationContext-dao.xml配置文件

当主配置文件被加载时,applicationContext-dao.xml也会被加载

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="applicationContext-dao.xml"/>
</beans>

getBean的两种方法

java 复制代码
package com.itheima.demo;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import com.itheima.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserDaoDemo {
    public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 方法一,通过id
        UserDao userDao = (UserDao) app.getBean("userDao");
        // 方法二: 通过类名,容器中不能出现两个同类型的bean
        UserDao userDao2 = app.getBean(UserDao.class);
        userDao.save();
    }
}

spring配置数据源

数据源的开发步骤

  1. 导入数据源和数据驱动坐标
  2. 创建数据源对象
  3. 设置数据源的基本连接数据
  4. 使用数据源获取链接资源和归还连接资源

常用坐标

xml 复制代码
<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>

        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

手动创建数据源

java 复制代码
public class SpringTest {
    // 手动创建druid数据源
    public void test2() throws SQLException {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/wt");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        DruidPooledConnection connection = dataSource.getConnection();
    }

    // 手动创建c3p0数据源
    @Test
    public void test1() throws PropertyVetoException, SQLException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/wt");
        dataSource.setUser("root");
        dataSource.setPassword("root");
        Connection connection = dataSource.getConnection();
    }
}

抽取配置文件配置数据源

在resource下创建jdbc.properties配置文件

将配置写在配置文件中

txt 复制代码
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/wt
jdbc.username=root
jdbc.password=root

测试代码

java 复制代码
// 加载配置文件形式手动创建c3p0数据源
    @Test
    public void test1() throws PropertyVetoException, SQLException {

        // ResourceBundle.getBundle的搜索路径时从resources开始,文件名不需要写后缀
        ResourceBundle rb = ResourceBundle.getBundle("jdbc");
        String driver = rb.getString("jdbc.driver");
        String url = rb.getString("jdbc.url");
        String username = rb.getString("jdbc.username");
        String password = rb.getString("jdbc.password");

        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass(driver);
        dataSource.setJdbcUrl(url);
        dataSource.setUser(username);
        dataSource.setPassword(password);
        Connection connection = dataSource.getConnection();
    }

spring产生数据源对象

配置bean

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/wt"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
</beans>

加载

java 复制代码
public class SpringTest {

    @Test
    public void test1() throws PropertyVetoException, SQLException {

        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContest.xml");
        DataSource dataSource = app.getBean(DataSource.class);
    }
}

spring配置资源文件

引入context命名空间和真实地址

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
">

配置

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
    <!--
        加载外部的配置文件
    -->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
</beans>

spring的注解

新注解

配置扫描

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
    <!--
        配置组件扫描,告诉spring在哪个包下的bean需要进行扫描进行创建对象
    -->
    <context:component-scan base-package="com.itheima"/>
</beans>

添加注解

java 复制代码
package com.itheima.dao.impl;

import com.itheima.dao.UserDao;
import org.springframework.stereotype.Repository;

@Repository("userDao")
public class UserDaoImpl implements UserDao {

    @Override
    public void save() {
        
    }
}

加载bean

java 复制代码
package com.itheima.service.impl;

import com.itheima.dao.UserDao;
import com.itheima.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service("userService")
public class UserServiceImpl implements UserService {
// 可用Resource替代这两个
// 注解方式注入可以不写set方法
    @Autowired 			// 按照数据类型进行匹配
    @Qualifier("userDao")     // 按照id的值从容器中进行匹配,必须结合Autowired一起用
    private UserDao userDao;

	

    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void save() {
        userDao.save();
    }
}

通过资源文件给变量赋值

加载资源文件

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
    <!--
        配置组件扫描,告诉spring在哪个包下的bean需要进行扫描进行创建对象
    -->
    <context:component-scan base-package="com.itheima"/>

<!--    加载资源文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
</beans>

配置注解赋值

java 复制代码
 	// 通过注解进行赋值
    @Value("${jdbc.driver}")
    private String driver;

新注解的使用

使用配置文件使用新注解

java 复制代码
package com.itheima.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;


@Configuration          // 标志该类是spring的核心配置类
@ComponentScan("com.itheima")       // 扫描指定路径
@PropertySource("classpath:jdbc.properties")        // 引入配置文件
@Import({DataSourceConfiguration.class})            // 加载子配置文件
public class SpringConfiguration {
    // 加载配置文件中的键值对
    @Value("${jdbc.Driver}")
    private String driver;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Bean("dataSource")     // spring 会将当前方法的返回值以指定名称存储到spring容器中
    public DataSource getDataSource() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass(driver);
        dataSource.setJdbcUrl(url);
        dataSource.setUser(username);
        dataSource.setPassword(password);
        return dataSource;
    }

}

加载新注解

java 复制代码
public class UserDaoDemo {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class)

    }
}

spring集成junit

集成之后不需要写类似下面的代码,可以直接注入需要测试的bean进行测试,这个工作由spring完成

java 复制代码
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class);

导入spring集成junit的坐标

xml 复制代码
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>

测试代码

java 复制代码
package com.itheima.test;

import com.itheima.config.SpringConfiguration;
import com.itheima.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)     // 指定测试内核
@ContextConfiguration("classpath:applicationContext.xml")           // xml文件配置
@ContextConfiguration(classes = {SpringConfiguration.class})           // 配置类注解进行配置
public class SpringTest {
    // 指定要测试的类
    @Autowired
    private UserService userService;


    @Test       // 进行测试
    public void test1() {

    }
}

spring集成web环境

添加坐标

xml 复制代码
			<dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.2.1</version>
            <scope>provided</scope>
        </dependency>

在main.webapp下创建WEB-INF.web.xml作为配置文件

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>

<web-app  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"


          version="3.1">

<!--
    配置监听器
-->
    <listener>
        <listener-class>it.heima.listener.ContextLoaderListener</listener-class>
    </listener>


<!--
    配置映射关系
-->
    <servlet>
        <servlet-name>UserServletImpl</servlet-name>
        <servlet-class>it.heima.web.impl.UserServletImpl</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>UserServletImpl</servlet-name>
        <url-pattern>/userServlet</url-pattern>
    </servlet-mapping>


</web-app>

创建Servlet

java 复制代码
package it.heima.web.impl;

import it.heima.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


public class UserServletImpl extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        ServletContext servletContext = req.getServletContext();
        ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");
        UserService userService = app.getBean(UserService.class);
        userService.save();
    }
}

创建应用上下文监听器,在项目启动的时候就通过ClassPathXmlApplicationContext("applicationContext.xml")创建上下文,不需要每次都自己创建

java 复制代码
package it.heima.listener;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

// 创建一个上下文监听器
public class ContextLoaderListener implements ServletContextListener {

    // 初始化方法
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 将Spring的应用上下文对象存储到ServletContext域中
        ServletContext servletContext = servletContextEvent.getServletContext();
        servletContext.setAttribute("app",app);
    }

    // 销毁方法
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }
}

优化耦合问题

解决applicationContext.xml耦合问题

在web.xml中创建全局参数

xml 复制代码
<!--
    配置全局初始参数
-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>applicationContext.xml</param-value>
    </context-param>

修改监听器代码,改成从全局参数获取applicationContext.xml文件名字

java 复制代码
package it.heima.listener;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

// 创建一个上下文监听器
public class ContextLoaderListener implements ServletContextListener {

    // 初始化方法
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {

        ServletContext servletContext = servletContextEvent.getServletContext();
        
        // 从web.xml中读取全局参数contextConfigLocation
        String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");


        ApplicationContext app = new ClassPathXmlApplicationContext(contextConfigLocation);
        // 将Spring的应用上下文对象存储到ServletContext域中

        servletContext.setAttribute("app",app);
    }

    // 销毁方法
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }
}

解决下面代码app耦合问题

java 复制代码
ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");

创建获取app的工具类

java 复制代码
package it.heima.listener;

import org.springframework.context.ApplicationContext;

import javax.servlet.ServletContext;

public class WebApplicationContextUtils {

    public static ApplicationContext getWebApplicationContext(ServletContext servletContext){
        return (ApplicationContext) servletContext.getAttribute("app");
    }
}

修改代码,从工具类中获取app

java 复制代码
package it.heima.web.impl;

import it.heima.listener.WebApplicationContextUtils;
import it.heima.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


public class UserServletImpl extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        ServletContext servletContext = req.getServletContext();
//        ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");

        // 优化后的代码,不需要使用app获取
        ApplicationContext app = (ApplicationContext) WebApplicationContextUtils.getWebApplicationContext(servletContext);
        UserService userService = app.getBean(UserService.class);
        userService.save();
    }
}

spring集成web环境

导入坐标

xml 复制代码
<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>

修改配置文件

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>

<web-app  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
          version="3.1">
    <servlet>
        <servlet-name>UserServletImpl</servlet-name>
        <servlet-class>it.heima.web.impl.UserServletImpl</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>UserServletImpl</servlet-name>
        <url-pattern>/userServlet</url-pattern>
    </servlet-mapping>

    <!--
        配置spring的监听器
    -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
<!--
    配置spring的全局初始参数
-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
</web-app>

通过spring的方法获取app

java 复制代码
package it.heima.web.impl;

import it.heima.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


public class UserServletImpl extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        ServletContext servletContext = req.getServletContext();
//        ApplicationContext app = (ApplicationContext) WebApplicationContextUtils.getWebApplicationContext(servletContext);
        // 使用spring提供的的方法获取app
        WebApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        UserService userService = app.getBean(UserService.class);
        userService.save();
    }
}

springMVC

springMVC是一种基于Java的实现MVC设计火星的请求驱动类型的轻量级web框架,属于SpringFrameWork的后续产品

开发springmvc的步骤


  1. 用户发送请求到前端控制器DispatcherServlet
  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器
  3. 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
  4. DispatcherServlet调用HandlerAdapter处理器适配器
  5. HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)
  6. Controller执行结束之后返回ModelAndView
  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
  8. DispatcherServlet将ModelAndView传给ViewReslove视图解析器
  9. ViewReslover解析后返回具体view
    10.DisoatcherServlet根据View进行渲染视图。DispatcherServlet相应用户

实现springMVC的基础步骤

导入坐标

xml 复制代码
<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.0.5.RELEASE</version>
       </dependency>

在web.xml中配置springMVC的前端控制器

xml 复制代码
<!--
配置springMVC的前端控制器
-->
    
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--        加载配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
<!--        配置加载时机-->
        <load-on-startup>1</load-on-startup>          
    </servlet>
    <!--配置映射地址-->
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

在resource中创建spring-mvc.xml配置springMVC的配置

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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">

<!--
    Controller的组件扫描
-->
    <context:component-scan base-package="it.heima.controller"/>

</beans>

编写Controller

java 复制代码
package it.heima.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class UserController {

    @RequestMapping("/quick")
    public String save(){
        System.out.println("Controller save running");
        // 返回视图
        return "seccess.jsp";
    }
}

springMVC中的注解

@RequestMapping:请求映射,对请求的虚拟地址(URL)映射到具体的方法上

参数:

value:指定请求的URL,它和path属性的作用是一样的

method:指定请求方法

params:指定限制请求参数的条件。

java 复制代码
package it.heima.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class UserController {

    // 必须带有accountName参数
    @RequestMapping(value = "/quick", method = RequestMethod.GET,params = {"accountName"})
    public String save(){
        System.out.println("Controller save running");
        // 返回视图
        return "/seccess.jsp";				// 默认为转发forward
        return "redirect:seccess.jsp";   // 重定向
    }
}

在spring-web.xml中手动配置内部资源视图解析器

xml 复制代码
<!--配置内部资源解释器-->
    <bean id="viewResolve" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--        配置前缀和后缀-->
        <property name="prefix" value="/jsp/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

ModelAndView两种使用方式

创建一个显示界面

jsp 复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>success</h1>
<%--    获取ModelAndView传来的键值对--%>
    <h1>username:${username}</h1>

</body>
</html>

ModelAndView的第一种使用

java 复制代码
package it.heima.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class UserController {
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public ModelAndView save(){
        /*
        Model: 模型,用于封装数据
        View:视图, 用于展示数据
         */
        ModelAndView modelAndView = new ModelAndView();
        // 设置视图名称(modelAndView会携带index.jsp返回,会显示这个界面)
        modelAndView.setViewName("seccess");
        // 设置model数据(把键值对一起返回,页面中可以根据键取出对应的内容)
        modelAndView.addObject("username","itcast");
        return modelAndView;
    }
}

方法二

java 复制代码
@Controller
public class UserController {
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public ModelAndView save(ModelAndView modelAndView){
        // 设置视图名称(modelAndView会携带index.jsp返回,会显示这个界面)
        modelAndView.setViewName("seccess");
        // 设置model数据(把键值对一起返回,页面中可以根据键取出对应的内容)
        modelAndView.addObject("username","itcast");
        return modelAndView;
    }
}

将model 和 View进行拆分

java 复制代码
@Controller
public class UserController {
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public String save(Model model){
        // 设置model数据(把键值对一起返回,页面中可以根据键取出对应的内容)
        model.addAttribute("username","itcast");
        // 返回视图
        return "seccess";
    }
}

通过原始方法返回数据

java 复制代码
@Controller
public class UserController {
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public String save(HttpServletRequest request){
        request.setAttribute("username","zhangsan");
        // 返回视图
        return "seccess";
    }
}

回写数据

传统web回写数据方法

java 复制代码
@Controller
public class UserController {

    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public void save(HttpServletResponse response) throws IOException {
        response.getWriter().print("helloword");
    }
}

通过注解方式进行回写

java 复制代码
@Controller
public class UserController {

    @ResponseBody     // 告诉框架不要进行页面跳转,直接进行页面回写
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public String save() {
        return "itheima";
    }
}

回写json数据

添加坐标

xml 复制代码
<dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.0</version>
        </dependency>

返回json

java 复制代码
@Controller
public class UserController {

    @ResponseBody
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public String save() throws JsonProcessingException {
    //UserDaoImpl 必须有get和set方法
        UserDaoImpl userDao = new UserDaoImpl();
        userDao.setUsername("zhangsan");
        userDao.setAge(18);

        // 使用jetson的转换工具将对象转换成json格式字符串,需要添加相应的坐标
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(userDao);
        return json;
    }
}

返回对象和集合

在spring-mvc.xml中配置处理器映射器,spring自动将对象转为json格式

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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
    
    <context:component-scan base-package="it.heima.controller"/>

    <!--
        配置处理器映射器,配置处理器映射器将返回的对象转为json格式
    -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
            </list>
        </property>
    </bean>
</beans>

写controller方法

java 复制代码
@Controller
public class UserController {

    @ResponseBody
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public UserDaoImpl save() {
        UserDaoImpl userDao = new UserDaoImpl();
        userDao.setUsername("zhangsan");
        userDao.setAge(30);
        return userDao;
    }
}

通过注解的方式将对象格式转为json,不需要再配置MappingJackson2HttpMessageConverter

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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
">

    <context:component-scan base-package="it.heima.controller"/>

<!--    mvc的注解驱动,自动集成MappingJackson2HttpMessageConverter-->
    <mvc:annotation-driven/>

</beans>

springmvc获取请求数据

常规方法

java 复制代码
@Controller
public class UserController {

    @ResponseBody
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public UserDaoImpl save(String username,int age) {
        UserDaoImpl userDao = new UserDaoImpl();
        userDao.setUsername(username);
        userDao.setAge(age);
        return userDao;
    }
}

获取POJO参数,要求属性名和参数名一致,springmvc会自动进行封装

java 复制代码
@Controller
public class UserController {

    @ResponseBody
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public UserDaoImpl save(UserDaoImpl userDao) {
        return userDao;
    }
}

获取数组类型的参数

java 复制代码
@Controller
public class UserController {

    @ResponseBody
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public void save(String[] str) {

    }
}

解决传递来的参数和接收的参数不一致的问题

请求传来参数name,用username接收

java 复制代码
@Controller
public class UserController {

    @ResponseBody
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    /*
        required = true如果请求时没有传递这个参数就报错
        defaultValue = "zhangsan"   默认值
     */
    public String save(@RequestParam(value = "name", required = true,defaultValue = "zhangsan") String username) {
        return username;
    }
}

获取Restful格式参数

Restful凤凤的请求是使用"URL+请求方式"表示一次请求的目的,有四种请求方式

GET:用于获取资源

POST:用于新建资源

PUT:用于更新资源

DELETE:用于删除资源

java 复制代码
@Controller
public class UserController {

    @ResponseBody
    @RequestMapping(value = "/quick/{username}", method = RequestMethod.GET)
    /*
        value = "/quick/{username}"的username接收到参数赋值给value = "username"中的username,然后value = "username"中的username赋值给username
     */
    public String save(@RequestParam(value = "username", required = true,defaultValue = "zhangsan") String username) {
        return username;
    }
}

获取请求头

使用@RequestHeader可以获得请求头信息

  • value:请求头的名称
  • required:是否必须携带此请求头
java 复制代码
@Controller
public class UserController {

    @ResponseBody
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public void save(@RequestHeader(value = "User-Agent") String UserAgnet) {
        System.out.println(UserAgnet);
    }
}

获取cookie的值

java 复制代码
@Controller
public class UserController {

    @ResponseBody
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public void save(@CookieValue(value = "JSESSIONID") String JSessionId) {
        System.out.println(JSessionId);
    }
}

配置静态资源

再spring-web.xml配置静态资源访问

xml 复制代码
<!--    mvc的注解驱动,自动集成MappingJackson2HttpMessageConverter-->
    <mvc:annotation-driven/>
    <!--方法一
        开放资源访问
        mapping="/js/**":映射地址,访问服务端时的地址
         location="/js/"哪个目录下是开放的
    -->
    <mvc:resources mapping="/js/**" location="/js/"/>
<!--    方法二:如何找不到资源则交给tomcat去找-->
    <mvc:default-servlet-handler/>

解决POST请求中文乱码

在web.xml配置UTF-8过滤器

xml 复制代码
<!--
    配置全局过滤器,对所有资源用UTF-8过滤,解决Post请求乱码问题
-->
    <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>

自定义类型转换器

  1. 定义转换器实现Converter接口
  2. 在配置文件中声明转换器
  3. 在中引用转换器
    实现一个转换器
java 复制代码
package it.heima.converter;

import org.springframework.core.convert.converter.Converter;

import javax.xml.crypto.Data;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DataConverter implements Converter<String,Data> {

    @Override
    public Data convert(String s) {
        // 将日期的字符串转换成日期对象,返回对象
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date parse =null;
        try {
            parse = format.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return (Data) parse;
    }
}

在spring-mvc.xml中配置转换器的注入

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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
">

    <context:component-scan base-package="it.heima.controller"/>

    <mvc:default-servlet-handler />

<!--指点转换服务工厂,将转换器注入到springmvc中-->
    <mvc:annotation-driven conversion-service="conversionService"/>

    <!--声明转换器-->
<!--
    定义一个转换器服务的工厂对象,工厂内部需要注入一个converters的列表,列表内为自定义转换器
    理解:创建ConversionServiceFactoryBean工厂的bean,让创建ConversionServiceFactoryBean工厂的bean给我们造DataConverter的转换器对象
-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="it.heima.converter.DataConverter"></bean>
            </list>
        </property>
    </bean>

</beans>

文件上传

文件上传三要素

  • 表单项type=file
  • 表单的提交方式是POST
  • 表单的enctype属性是多部份表单形式,及enctype="multipart/form-data"

文件上传步骤

  • 导入坐标
  • 配置文件上传解析器
  • 编写文件上传代码

导入坐标

xml 复制代码
<dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.3</version>
        </dependency>

配置文件上传解析器

xml 复制代码
<!--    配置文件上传解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="UTF-8"></property>
        <property name="maxUploadSize" value="500000"></property>
    </bean>

JdbcTemplate

  1. 导入坐标
  2. 创建数据库表和实体
  3. 创建JdbcTemplate对象
  4. 执行数据库操作

导入坐标

xml 复制代码
<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>

执行程序

java 复制代码
package com.itheima.domain;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;

import java.beans.PropertyVetoException;

public class jdbctext {
    @Test
    public void test1() throws PropertyVetoException {
        // 创建一个数据源对象
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/wt");
        dataSource.setUser("root");
        dataSource.setPassword("root");


        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        // 设置数据源
        jdbcTemplate.setDataSource(dataSource);
       // 执行操作   增删改都是用update
        int tom = jdbcTemplate.update("insert into user values(?,?)", "tom", 50);
        List<UserDaoImpl> query = jdbcTemplate.query("select * from user", new BeanPropertyRowMapper<UserDaoImpl>(UserDaoImpl.class));
        System.out.println(tom);
    }
}

springMVC的拦截器

interceptor是专属于springmvc的拦截器

自定义一个拦截器需要三步

  1. 创建拦截器类实现HandlerInterceptor接口
  2. 配置拦截器
  3. 测试拦截器的拦截效果

创建拦截器

java 复制代码
package it.heima.Interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {
    @Override
    // 在目标方法执行之前执行
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("pre");
        String param = request.getParameter("param");
        if (param.equals("yes")){
            return true;    // 放行
        }else {
            request.getRequestDispatcher("/error.jsp").forward(request,response);
            return false;            //不放行,并进行重定向
        }
        
    }

    @Override
    // 在目标方法执行之后,视图返回之前执行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("post");
    }

    @Override
    // 整个流程都执行完毕之后
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("after");
    }
}

配置拦截器

xml 复制代码
<!--    配置拦截器-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--
            对哪些资源进行拦截 /**表示所有资源
        -->
        <mvc:mapping path="/**"/>
        <!--配置哪些资源不在拦截操作之内-->
        <mvc:exclude-mapping path="/user/login"/>
        <bean class="it.heima.Interceptor.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

springMVC的异常处理机制

springMVC提供了简单异常处理器SimpleMappingExceptionResolver

使用Spring的异常处理接口HandlerExceptionResolver自定义异常处理方法

自定义异常处理器

java 复制代码
package it.heima.resolver;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        return null;
    }
}

配置异常处理器

xml 复制代码
<!--简单异常配置-->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!--默认异常处理,当下面的匹配不到时使用这个-->
        <property name="defaultErrorView" value="error"/>
        <property name="exceptionMappings">
            <map>
                <!--java.lang.ClassCastException,则跳到error视图-->
                <entry key="java.lang.ClassCastException" value="error"/>
            </map>
        </property>
    </bean>

    <!--配置自定义异常处理器-->
    <bean class="it.heima.resolver.MyExceptionResolver"/>

AOP面向切片编程

通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术

JDK的动态代理

创建目标类

java 复制代码
package com.itheima.proxy.jdk.impl;

import com.itheima.proxy.jdk.TargetInterface;

public class Target implements TargetInterface {
    public void save() {
        System.out.println("save");
    }
}

创建增强类

java 复制代码
package com.itheima.proxy.jdk.impl;

public class Advice {
    public void before(){
        System.out.println("前置增强");
    }

    public void postRunning(){
        System.out.println("后置增强");
    }
}

创建代理

java 复制代码
package com.itheima.proxy.jdk.impl;

import com.itheima.proxy.jdk.TargetInterface;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {

    public static void main(final String[] args) {
        // 创建目标对象
        final Target target = new Target();

        // 创建增强对象
        final Advice advice = new Advice() ;


        // 返回动态生成的代理对象
        TargetInterface proxy = (TargetInterface)Proxy.newProxyInstance(
                // 目标对象的类加载器
                target.getClass().getClassLoader(),   // 目标对象类加载器
                // 目标对象相同的接口子界面对象数组
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    // 调用代理对象的任何方法 实质执行的都是invoke方法
                    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                        advice.before();    // 前置增强
                        Object invoke = method.invoke(target, args);// 目标对象
                        advice.postRunning();      // 后置增强
                        return invoke;
                    }
                }
        );
        // 调用代理对象的方法
        proxy.save();
    }
}

cglib的动态代理

java 复制代码
package com.itheima.proxy.cglib;

import com.itheima.proxy.jdk.impl.Advice;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class ProxyTest {

    public static void main(final String[] args) {
        // 创建目标对象
        final Target target = new Target();

        // 创建增强对象
        final Advice advice = new Advice() ;


        // 返回动态生成的代理对象,基于cglib
        // 1. 创建增强其
        Enhancer enhancer = new Enhancer();
        // 2. 设置父类(目标)
        enhancer.setSuperclass(com.itheima.proxy.cglib.Target.class);
        // 3. 设置回调
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                advice.before();    // 前置增强
                Object invoke = method.invoke(target, args);// 目标对象
                advice.postRunning();      // 后置增强
                return invoke;
            }
        });

        // 4. 创建代理对象
        Target proxy = (Target) enhancer.create();

        proxy.save();
    }
}

AOP

spring的AOP实现底层就是对动态代理的代码进行封装,封装后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强

AOP的相关术语

  • Target:代理的目标对象
  • proxy: 一个类被AOP织入增强后,就产生一个代理类
  • Joinpoint: 连接点,被拦截到的点,在spring中,这些点指的是方法(可以被增强的方法都叫做连接点)
  • Pointcut: 切入点,我们要对哪些连接点进行拦截,这些连接点叫切入点
  • advice: 增强/通知,拦截到切入点后要做的事情
  • Aspect: 切面,切入点和通知的结合
  • Weaving: 织入,将切点和增强结合的过程

AOP需要编写的内容

  • 编写核心业务代码
  • 编写切面类,切面类中有通知
  • 在配置文件中,配置织入关系,即哪些通知和哪些连接点进行结合

AOP技术实现的内容

spring框架监控切入点方法的执行,一旦监控到切入点方法被运行,使用代理记之,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行

基于XML的AOP开发

AOP的快速入门

  1. 导入坐标
  2. 创建目标接口和目标类
  3. 创建切面类
  4. 在目标类和切面类的对象创建权交给spring
  5. 在applicationContext.xml中配置织入关系
  6. 测试代码

导入坐标

xml 复制代码
<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.4</version>
        </dependency>

写目标类

java 复制代码
package com.itheima.aop;

public class Target implements TargetInterface {
    public void save() {
        System.out.println("save");
    }
}

写增强类

java 复制代码
package com.itheima.aop;

public class MyAspect {

    public void before(){
        System.out.println("前置增强");
    }


}

配置切面

java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <!--配置目标对象-->
    <bean id="target" class="com.itheima.aop.Target"/>
    <!--配置切面对象-->
    <bean id="myAspect" class="com.itheima.aop.MyAspect"></bean>
    
    <!--配置织入,告诉spring框架哪些方法需要进行哪些增强-->
    <aop:config>
        <!--
            声明切面,告诉spring切面是谁
        -->
        <aop:aspect ref="myAspect">
        <!--
            对public void com.itheima.aop.Target.save()方法使用myAspect切面对象的before方法进行增强
        -->
            <aop:before method="before" pointcut="execution(public void com.itheima.aop.Target.save())"></aop:before>
        </aop:aspect>
    </aop:config>

</beans>

测试

java 复制代码
package test;


import com.itheima.aop.TargetInterface;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Test {

    @Autowired
    private TargetInterface target;

    @org.junit.Test
    public void test1(){
        target.save();
    }

}

基于注解的aop开发

  1. 创建目标接口和目标类
  2. 创建切面类
  3. 将目标类和切面类的对象创建权交给spring
  4. 在切面类中使用注解配置织入关系
  5. 在配置文件中开启组件扫描和AOP的自动代理
  6. 测试

创建目标接口

java 复制代码
package com.itheima.anno;

public interface TargetInterface {
    public void save();
}

创建目标类

java 复制代码
package com.itheima.anno;

import org.springframework.stereotype.Component;

// 将目标交给spring容器
@Component("target")
public class Target implements TargetInterface {
    public void save() {
        System.out.println("save");
    }
}

创建切面类,并将切面类的对象创建权交给spring

java 复制代码
package com.itheima.anno;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

// 将切面对象交给spring
@Component("myAspect")
@Aspect         //告诉spring容器这是个切面类
public class MyAspect {

    // 配置前置增强,对anno下的所有类中的所有方法进行增强
    @Before("execution(* com.itheima.anno.*.*(..))")
    public void before(){
        System.out.println("前置增强");
    }


}

配置组件扫描和aop自动代理

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--配置组件扫描-->
    <context:component-scan base-package="com.itheima"/>

    <!--aop自动代理-->
    <aop:aspectj-autoproxy/>


</beans>

测试

java 复制代码
package test;



import com.itheima.anno.TargetInterface;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Test {

    @Autowired
    private TargetInterface target;

    @org.junit.Test
    public void test1(){
        target.save();
    }
}

spring的事务控制

PlatformTransactionManager接口是spring的事务管理器

TransactionStatus getTransaction 获取事务的状态信息

void commit 提交事务

void rollback 回滚事务

TransactionDefinition是事务的定义信息对象

interesting getIsolationLevel 设置事务的隔离级别

int getPropogationBehavior 获得事务的传播行为

int getTimeout 获取超时时间

boolean isReadOnly 是否只读

事务的传播行为:解决业务方法调用业务方法时,他们之间事务统一性的问题

REQUIRED:A掉B,B看A中有没有事务,如果A有事务,B用A的事务,如果A没有事务,则B自己创建一个事务

SUPPORTS:A掉B,B看A中有没有事务,如果A有事务,B用A的事务,如果A没有事务,则B通过非事务方式运行

MANDATORY:A掉B,B看A中有没有事务,如果A有事务,B用A的事务,如果A没有事务,抛出异常

MANDATORY:A掉B,B看A中有没有事务,如果A有事务,B用A的事务,如果A没有事务,抛出异常

超时时间:默认值是-1,没有超时限制,如果有,以秒为单位进行设置

TransactionStatus接口提供的是事务具体的运行状态

boolean hasSavepoint 是否存储回滚点

boolean isCompleted() 事务是否完成

Boolean isNewTransaction 是否是新事物

boolean isRollbackOnly 事务是否回滚

声明式事务控制配置

java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
">

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/wt"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
    <!-- 目标对象  内部的方法就是切点 -->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>
    <!-- 配置平台事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 通知  事务的增强 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 设置事务的属性信息的 -->
        <tx:attributes>
            <!--
                name="transfer"对指定方法采用各种配置
                isolation="REPEATABLE_READ"隔离级别
            -->
            <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
            <tx:method name="save" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
            <tx:method name="findAll" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
            <tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
    <!-- 配置事务的aop织入 -->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.itheima.service.impl.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
</beans>

基于注解的声明事务控制

设置事务的增强,并织入AOP

java 复制代码
package com.itheima.service.impl;

import com.itheima.dao.AccountDao;
import com.itheima.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service("accountService")
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

    // 设置事务的增强,并织入AOP
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public void transfer(String outMan, String inMan, double money) {
        accountDao.out(outMan,money);
        int i = 1/0;
        accountDao.in(inMan,money);
    }
}

配置事务注解驱动

xml 复制代码
    <!--添加事务注解驱动-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

mybatis

mybatis开发步骤

  1. 添加坐标
  2. 创建user数据表
  3. 编写User实体类
  4. 编写映射文件UserMapper.xml
  5. 编写核心文件SqlMapConfig.xml
  6. 编写测试

添加坐标

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>untitled2</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring_mybatis</artifactId>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

</project>

创建实体类

java 复制代码
package com.itheima.domain;

public class User {

    private int id;
    private String username;
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

编写映射文件UserMapper.xml

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">
<mapper namespace="userMapper">

    <!--删除操作-->
    <delete id="delete" parameterType="int">
        delete from user where id=#{abc}
    </delete>

    <!--修改操作-->
    <update id="update" parameterType="com.itheima.domain.User">
        update user set username=#{username},password=#{password} where id=#{id}
    </update>

    <!--插入操作-->
    <insert id="save" parameterType="com.itheima.domain.User">
        insert into user values(#{id},#{username},#{password})
    </insert>

    <!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>

    <!--根据id进行查询-->
    <select id="findById" resultType="user" parameterType="int">
        select * from user where id=#{id}
    </select>

</mapper>

编写核心文件

两种事务管理器

JDBC:这个配置就是直接使用JDBC的提交和回滚,它依赖于从数据源得到的链接来管理事务作用域

MANAGED:这个事务管理器什么都不做,没有提交和回滚

数据源类型

  • UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭链接
  • POOLED:这种数据源的实现利用"池"的概念,将JDBC链接对象组织起来
  • JNDI:这种数据源的实现是为了能在如EJB或应用服务器这类容器使用,容器可以几种或在外部配置数据源,然后防止一个JNDI上下文的引用

mapper标签加载映射文件方法

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!--通过properties标签加载外部properties文件-->
    <properties resource="jdbc.properties"></properties>

    <!--自定义别名-->
    <typeAliases>
        <typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>
    </typeAliases>

    <!--数据源环境,default="developement"指定默认环境名称-->
    <environments default="developement">
    	<!--id="developement"指定当前环境名称-->
        <environment id="developement">
            <!--指定使用JDBC事务管理器-->
            <transactionManager type="JDBC"></transactionManager>
            <!--数据源类型-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    

    <!--加载映射文件-->
    <mappers>
        <mapper resource="com/itheima/mapper/UserMapper.xml"></mapper>
    </mappers>


</configuration>

测试

java 复制代码
package com.itheima.test;

import com.itheima.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyBatisTest {


    @Test
    //删除操作
    public void test4() throws IOException {

        //获得核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session回话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行操作  参数:namespace+id
        sqlSession.delete("userMapper.delete",8);

        //mybatis执行更新操作  提交事务
        sqlSession.commit();

        //释放资源
        sqlSession.close();
    }

    @Test
    //修改操作
    public void test3() throws IOException {

        //模拟user对象
        User user = new User();
        user.setId(7);
        user.setUsername("lucy");
        user.setPassword("123");

        //获得核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session回话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行操作  参数:namespace+id
        sqlSession.update("userMapper.update",user);

        //mybatis执行更新操作  提交事务
        sqlSession.commit();

        //释放资源
        sqlSession.close();
    }

    @Test
    //插入操作
    public void test2() throws IOException {

        //模拟user对象
        User user = new User();
        user.setUsername("xxx");
        user.setPassword("abc");

        //获得核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session回话对象,参数true表示自动提交事务
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //执行操作  参数:namespace+id
        sqlSession.insert("userMapper.save",user);

        //mybatis执行更新操作  提交事务
        //sqlSession.commit();

        //释放资源
        sqlSession.close();
    }

    @Test
    //查询操作
    public void test1() throws IOException {
        //获得核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session回话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行操作  参数:namespace+id
        List<User> userList = sqlSession.selectList("userMapper.findAll");
        //打印数据
        System.out.println(userList);
        //释放资源
        sqlSession.close();
    }

    @Test
    //查询一个对象
    public void test5() throws IOException {
        //获得核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session回话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行操作  参数:namespace+id
        User user = sqlSession.selectOne("userMapper.findById", 1);
        //打印数据
        System.out.println(user);
        //释放资源
        sqlSession.close();
    }

}

MyBatis的dao实现

Mybatis代理开发方式实现DAO层的开发

Mapper.xml文件中的namespace与Mapper配置接口的全限定名相同

Mapper接口方法名和Mapper.xml中的id相同

Mapper接口方法的输入参数和返回值类型要和Mapper.xml中的相同

mybatis的动态sql

动态sql中if的使用

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">
<mapper namespace="com.itheima.mapper.UserMapper">
    <select id="findBycondition" parameterType="user" resultType="user">
        select * from user
        <where>
            <if test="id!=0">
                id=#{id}
            </if>
            <if test="username!=null">
                and username=#{username}
            </if>
            <if test="password!=null">
                and password=#{password}
            </if>
        </where>
    </select>

</mapper>

foreach循环的使用

xml 复制代码
    <select id="findByIds" parameterType="list" resultType="user">
        select * from user
        <where>
        <!--
            遍历collection="list"变量的值
             open="id in ("  前置内容
             close=")"  后置内容
             item="id"      遍历的填充变量
             separator=","     分隔符
        -->
            <foreach collection="list" open="id in (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>
    </select>

sql语句抽取

xml 复制代码
    <!--抽取sql语句-->
    <sql id="selectUser">select * from user</sql>

    <select id="findBycondition" parameterType="user" resultType="user">
        <include refid="selectUser"></include>
        <where>
            <if test="id!=0">
                id=#{id}
            </if>
            <if test="username!=null">
                and username=#{username}
            </if>
            <if test="password!=null">
                and password=#{password}
            </if>
        </where>
    </select>

核心配置typeHandlers

jdbc和java中的数据类型是不一样的,类型处理器可以进行两者之间的类型转换

typeHandlers标签可以自定义类型转换器

创建类型转换器或者重写类型转换器:可以实现org.apache.ibatis.type.TypeHandler接口或者继承org.apache.ibatis.type.BaseTypeHandler,然后可以选择性地将它映射到一个JDBC类型

开发步骤:

  • 定义转换类继承类
  • 覆盖4个未实现的方法,其中setNonNullParameter为java程序设置数据到数据库的回调方法,getNullableResult为查询时mysql的字符串类型转换为java的Type类型的方法
  • 在MyBatiss核心配置文件中进行注册
  • 测试转换是否正确

自定义类型处理器

java 复制代码
package com.itheima.handler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

public class DataHandler extends BaseTypeHandler<Date> {
    // 将java类型转为数据库需要的类型
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
        long time = date.getTime();
        preparedStatement.setLong(i,time);
    }
    // 将数据库类型转为java类型
    //  String s  数据库中要转换的字段名
    // ResultSet resultSet查询出的结果集
    @Override
    public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
        // 获得结果集中需要的数据转换成Date类型
        long aLong = resultSet.getLong(s);
        Date date = new Date(aLong);
        return date;
    }
    // 将数据库类型转为java类型
    @Override
    public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
        long aLong = resultSet.getLong(i);
        Date date = new Date(aLong);
        return date;
    }
    // 将数据库类型转为java类型
    @Override
    public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        long aLong = callableStatement.getLong(i);
        Date date = new Date(aLong);
        return date;
    }
}

在核心配置文件配置

xml 复制代码
<!--    自定义注册类型处理器-->
    <typeHandlers>
        <typeHandler handler="com.itheima.handler.DataHandler"></typeHandler>
    </typeHandlers>

plugins分页助手

  1. 导入坐标
  2. 在mybatis核心配置文件中配置PageHelper
  3. 测试

导入坐标

xml 复制代码
    <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>3.7.5</version>
        </dependency>
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>0.9.1</version>
        </dependency>

配置分页助手

xml 复制代码
<!--    配置分页助手插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/>
        </plugin>
    </plugins>

测试

java 复制代码
package com.itheima.test;

import com.github.pagehelper.PageHelper;
import com.itheima.domain.User;
import com.itheima.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyBatisTest {


    @Test
    //查询操作
    public void test1() throws IOException {
        //获得核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session回话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        // 设置相关参数
        PageHelper.startPage(1,3);
        List<User> userList = mapper.findAll();
// 获得分页相关的参数
        PageInfo<User> pageInfo = new PageInfo<User>(userList);
        // 获取当前页
        System.out.println(pageInfo.getPageNum());
        // 每页显示条数
        pageInfo.getPageSize();
        // 总条数
        pageInfo.getTotal();
        // 总页数
        pageInfo.getPrePage();
        // 上一页
        pageInfo.getPrePage();
        // 是否为第一页
        pageInfo.isIsFirstPage();
        sqlSession.close();
    }


}

多表查询

一对一

构建数据表

java 复制代码
package com.itheima.domain;

import java.util.Date;

public class Orders {
    private int id;
    private Date ordertime;
    private double total;

    private User user;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Date getOrdertime() {
        return ordertime;
    }

    public void setOrdertime(Date ordertime) {
        this.ordertime = ordertime;
    }

    public double getTotal() {
        return total;
    }

    public void setTotal(double total) {
        this.total = total;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "orders{" +
                "id=" + id +
                ", ordertime=" + ordertime +
                ", total=" + total +
                ", user=" + user +
                '}';
    }
}
java 复制代码
package com.itheima.domain;

import javax.xml.crypto.Data;
import java.util.Date;

public class User {

    private int id;
    private String username;
    private String password;
    private Date bitrhday;

    public int getId() {
        return id;
    }

    public Date getBitrhday() {
        return bitrhday;
    }

    public void setBitrhday(Date bitrhday) {
        this.bitrhday = bitrhday;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

构建Mapper

java 复制代码
package com.itheima.mapper;

import com.itheima.domain.Orders;

import java.util.List;

public interface OrderMapper {
    public List<Orders> findAll();
}

一对多

修改user类

java 复制代码
package com.itheima.domain;

import java.util.Date;
import java.util.List;

public class User {

    private int id;
    private String username;
    private String password;
    private Date bitrhday;
    private List<Orders> ordersList;

    public List<Orders> getOrdersList() {
        return ordersList;
    }

    public void setOrdersList(List<Orders> ordersList) {
        this.ordersList = ordersList;
    }


    public int getId() {
        return id;
    }

    public Date getBitrhday() {
        return bitrhday;
    }

    public void setBitrhday(Date bitrhday) {
        this.bitrhday = bitrhday;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

构建Mapper

java 复制代码
package com.itheima.mapper;

import com.itheima.domain.User;

import java.util.List;

public interface UserMapper {
    public List<User> findAll();


}

配置映射关系

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">
<mapper namespace="com.itheima.mapper.UserMapper">

    <resultMap id="userMap" type="user">
        <id column="uid" property="id"></id>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        <result column="birthday" property="birthday"></result>
        <!--
            property="orderList" 集合名称
            ofType="order"当前集合的数据类型
        -->
        <collection property="ordersList" ofType="com.itheima.domain.Orders">
            <!--
                封装order的数据
            -->
            <id column="oid" property="id"></id>
            <result column="ordertime" property="ordertime"></result>
            <result column="total" property="total"></result>
        </collection>

    </resultMap>

    <select id="findAll" resultMap="userMap">
        Select *, o.id oid from USER u, orders o where u.id=o.id
    </select>


</mapper>

测试

java 复制代码
package com.itheima.test;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.domain.Orders;
import com.itheima.domain.User;
import com.itheima.mapper.OrderMapper;
import com.itheima.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyBatisTest {


    @Test
    //查询操作
    public void test1() throws IOException {
        //获得核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session回话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        UserMapper mapper = (UserMapper) sqlSession.getMapper(UserMapper.class);

        List<User> userList = mapper.findAll();
        for (User user:userList
             ) {
            System.out.println(user);
        }


        sqlSession.close();
    }

}

多对多

修改User代码

java 复制代码
package com.itheima.domain;

import java.util.Date;
import java.util.List;

public class User {

    private int id;
    private String username;
    private String password;
    private Date bitrhday;
    private List<Orders> ordersList;

    public List<Orders> getOrdersList() {
        return ordersList;
    }

    // 描述当前用户具备哪些角色
    private List<Role> roleList;

    public List<Role> getRoleList() {
        return roleList;
    }

    public void setRoleList(List<Role> roleList) {
        this.roleList = roleList;
    }

    public void setOrdersList(List<Orders> ordersList) {
        this.ordersList = ordersList;
    }


    public int getId() {
        return id;
    }

    public Date getBitrhday() {
        return bitrhday;
    }

    public void setBitrhday(Date bitrhday) {
        this.bitrhday = bitrhday;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", bitrhday=" + bitrhday +
                ", ordersList=" + ordersList +
                ", roleList=" + roleList +
                '}';
    }
}

修改配置

java 复制代码
<?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">
<mapper namespace="com.itheima.mapper.UserMapper">

    <resultMap id="userRoleMap" type="user">
        <!-- user的信息 -->
        <id column="userId" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="birthday" property="birthday"/>


        <!-- user内部的roleList信息 -->
        <collection property="roleList" ofType="role">
            <id column="roleId" property="id"/>
            <result column="roleName" property="roleName"/>
            <result column="roleDesc" property="roleDesc"/>
        </collection>
    </resultMap>

    
    <select id="findUserAndRoleAll" resultMap="userRoleMap"> SELECT * FROM USER u,sys_user_role ur,sys_role r WHERE u.id=ur.userId AND ur.roleId=r.id </select>
    
</mapper>

mybatis注解开发

Mapper

java 复制代码
package com.itheima.mapper;

import com.itheima.domain.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

public interface UserMapper {

    @Insert("insert into user values(#{id},#{username},#{password},#{birthday})")
    public void save(User user);

    @Update("update user set username=#{username},password=#{password} where id=#{id}")
    public void update(User user);

    @Delete("delete from user where id=#{id}")
    public void delete(int id);

    @Select("select * from user where id=#{id}")
    public User findById(int id);

    @Select("select * from user")
    public List<User> findAll();

    @Select("select * from user")
    // 通过Results封装返回结果
    @Results({
            @Result(id=true ,column = "id",property = "id"),
            @Result(column = "username",property = "username"),
            @Result(column = "password",property = "password"),
            @Result(
                    property = "orderList",
                    column = "id",
                    javaType = List.class,
                    many = @Many(select = "com.itheima.mapper.OrderMapper.findByUid")
            )
    })
    public List<User> findUserAndOrderAll();


    @Select("SELECT * FROM USER")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "username",property = "username"),
            @Result(column = "password",property = "password"),
            @Result(
                    property = "roleList",
                    column = "id",
                    javaType = List.class,
                    many = @Many(select = "com.itheima.mapper.RoleMapper.findByUid")
            )
    })
    public List<User> findUserAndRoleAll();


}

修改核心配置,加载映射关系

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <properties resource="jdbc.properties"></properties>

    <typeAliases>
        <typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>
    </typeAliases>

    <environments default="developement">
        <environment id="developement">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>


    <!--加载映射关系-->
    <mappers>
        <!--指定接口所在的包,扫描包内的接口-->
        <package name="com.itheima.mapper"/>
    </mappers>
</configuration>

Result标签封装结果的两种方式

java 复制代码
package com.itheima.mapper;

import com.itheima.domain.Order;
import com.itheima.domain.User;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface OrderMapper {



    @Select("select * from orders where uid=#{uid}")
    public List<Order> findByUid(int uid);
    
    @Select("select * from orders")
    @Results({
            @Result(column = "id",property = "id"),
            @Result(column = "ordertime",property = "ordertime"),
            @Result(column = "total",property = "total"),
            @Result(
                    property = "user", //要封装的属性名称
                    column = "uid", //根据那个字段去查询user表的数据
                    javaType = User.class, //要封装的实体类型
                    //select属性 代表查询那个接口的方法获得数据
                    one = @One(select = "com.itheima.mapper.UserMapper.findById")
            )
    })
    public List<Order> findAll();



    /*@Select("select *,o.id oid from orders o,user u where o.uid=u.id")
    @Results({
            @Result(column = "oid",property = "id"),
            @Result(column = "ordertime",property = "ordertime"),
            @Result(column = "total",property = "total"),
            @Result(column = "uid",property = "user.id"),
            @Result(column = "username",property = "user.username"),
            @Result(column = "password",property = "user.password")
    })
    public List<Order> findAll();*/
}
相关推荐
凉、介5 小时前
U-Boot 多 CPU 执行状态引导
java·服务器·前端
csdn_clwjc5 小时前
synchronized 锁升级
java·juc
脚大江山稳5 小时前
docker使用nginxWebUI配置
java·docker·容器
Miraitowa_cheems5 小时前
LeetCode算法日记 - Day 34: 二进制求和、字符串相乘
java·算法·leetcode·链表·职场和发展
CHANG_THE_WORLD5 小时前
C++并发编程指南 std::promise 介绍与使用
java·开发语言·c++·promise
Bonnie_12155 小时前
01-线上问题处理-树形结构拼接
java
重生成为编程大王5 小时前
FreeMarker快速入门指南
java·后端
tangweiguo030519875 小时前
Android应用完全重启指南:从任务重置到进程重生
android
2501_916007475 小时前
uni-app iOS 文件调试常见问题与解决方案:结合 itools、克魔、iMazing 的实战经验
android·ios·小程序·https·uni-app·iphone·webview