Spring进阶(一)

Spring整合Mybatis

  1. 将MyBatis的DataSource交给Spring IoC容器创建并管理,使用第三方数据库连接池(Druid,C3P0等)代替MyBatis内置的数据库连接池
  2. 将MyBatis的SqlSessionFactory交给Spring IoC容器创建并管理,使用spring-mybatis整合jar包中提供的SqlSessionFactoryBean类代替项目中的MyBatisUtil工具类
  3. 将MyBatis的接口代理方式生成的实现类,交给Spring IoC容器创建并管理

Mybatis核心对象分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//1.创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionfactoryBuilder()
//2.加载SqlMapconfig.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");,
//3.创建sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory
=sqlSessionFactoryBuilder.build(inputstream);
//4.获取sqlSession
SqlSession sqlSession=sqlsessionFactory.openSession();
//5.执行SqlSession对象执行查询,获取结果user
AccountDao accountDao =sqlSession.getMapper(AccountDao.class)
Account ac =accountDao.findById(2);
System.out.println(ac);
//释放资源
sqlsession.close();

配置文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 <?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>
<!--起别名-->
<typeAliases>
<package name="com.hngy.pojo"/>
</typeAliases>

<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false&amp;useServerPrepStmts=true"/>
<property name="username" value="username"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--扫描mapper-->
<package name="com.hngy.mapper"/>
</mappers>
</configuration>

利用Spring开始整合

  1. 导入相应的maven坐标
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<dependencies>
<!-- Junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

<!-- MyBatis核心Jar包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>

<!-- MySql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>

<!-- Lombok工具 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>

<!-- Spring核心 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.3</version>
</dependency>

<!-- Spring-test测试 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.3</version>
<scope>test</scope>
</dependency>

<!-- slf4j日志包 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>

<!-- druid阿里的数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>


<!-- Spring整合ORM 自动导入spring-orm,spring-jdbc,spring-tx-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.3</version>
</dependency>

<!-- Spring整合MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>

</dependencies>

  1. 设置配置文件
  • 设置Spring配置,通过注解的方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Configuration
    //要扫的包
    @ComponentScan("com.itheima")
    //@PropertySource:加载类路径jdbc.properties文件
    @PropertySource("classpath:jdbc.properties")
    //将jdbc和mybatis的配置加入到要扫的包下
    @Import({JdbcConfig.class,MybatisConfig.class})
    public class SpringConfig {
    }
  • 配置jdbc.properties,创建jdbcConfig

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    import com.alibaba.druid.pool.DruidDataSource;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import javax.sql.DataSource;

    public class JdbcConfig {
    @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
    public DataSource dataSource(){
    DruidDataSource ds = new DruidDataSource();
    ds.setDriverClassName(driver);
    ds.setUrl(url);
    ds.setUsername(userName);
    ds.setPassword(password);
    return ds;
    }
    }
  • 配置MybatisConfig

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
        import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.mapper.MapperScannerConfigurer;
    import org.springframework.context.annotation.Bean;
    import javax.sql.DataSource;

    public class MybatisConfig {
    //定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
    SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
    //设置MyBatis的别名解析路径,MyBatis会在这个包下查找类,并为这些类创建别名
    ssfb.setTypeAliasesPackage("com.itheima.domain");
    ssfb.setDataSource(dataSource);
    return ssfb;
    }
    //定义bean,返回MapperScannerConfigurer对象
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
    MapperScannerConfigurer msc = new MapperScannerConfigurer();
    //设置要扫的包
    msc.setBasePackage("com.itheima.dao");
    return msc;
    }
    }

    - 使用

    ```java
    import com.itheima.config.SpringConfig;
    import com.itheima.domain.Account;
    import com.itheima.service.AccountService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;

    public class App2 {
    public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

    AccountService accountService = ctx.getBean(AccountService.class);

    Account ac = accountService.findById(1);
    System.out.println(ac);
    }
    }

SpringMvc

  1. 一种基于Java实现MVC模型的轻量级Web框架

  2. web程序工作流程、

三层架构

  • web程序通过浏览器访问前端页面,发送异步请求到后端服务器

  • 后台服务器采用三层架构进行功能开发

    • 表现层负责接收请求和数据然后将数据转交给业务层
    • 业务层负责调用数据层完成数据库表的增删改查,并将结果返给表现层
    • 表现层将数据转换成json格式返回给前端
  • 前端页面将数据进行解析最终展示给用户。

表现层与数据层的技术选型:

  • 数据层采用Mybatis框架
  • 变现层采用SpringMVC框架,SpringMVC主要负责的内容有:
    • controller如何接收请求和数据
    • 如何将请求和数据转发给业务层
    • 如何将响应数据转换成json发回到前端

SpringMVC程序流程

1.浏览器发送请求到Tomcat服务器

2.Tomcat服务器接收到请求后,会将请求交给SpringMVC中的==DispatcherServlet[前端控制器]==来处理请求

3.DispatcherServlet不真正处理请求,只是按照对应的规则将请求分发到对应的Bean对象

4.Bean对象是有我们自己编写来处理不同的请求,每个Bean中可以处理一个或多个不同的请求url

5.DispatcherServlet和Bean对象都需要交给Spring容器来进行管理

拦截器

  1. 拦截器和过滤器的区别

归属不同:Filter属于servlet技术,Interceptor属于SpringMVc技术
拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVc的访问进行增强

  1. 拦截器执行顺序

preHandle
return true
controller
postHandle
afterCompletion
return false
结束

  1. 拦截器链的运行顺序
    preHandle:与配置顺序相同,必定运行
    postHandle:与配置顺序相反,可能不运行
    aftercompletion:与配置顺序相反,可能不运行

  2. 入门案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.itheima.controller.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {
@Override
//原始方法调用前执行的内容
//返回值类型可以拦截控制的执行,true放行,false终止
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String contentType = request.getHeader("Content-Type");
HandlerMethod hm = (HandlerMethod)handler;
System.out.println("preHandle..."+contentType);
return true;
}

@Override
//原始方法调用后执行的内容
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}

@Override
//原始方法调用完成后执行的内容
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}

  1. 配置类中配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.itheima.config;

import com.itheima.controller.interceptor.ProjectInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;

/*静态资源过滤*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
}

@Override
protected void addInterceptors(InterceptorRegistry registry) {
//配置拦截器
registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
}
}

具体实现

  • 导入坐标
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--1. 导入SpringMVC与servlet的坐标--> 
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
  • 创建控制器类, @Controller位于SpringMVC控制器类定义上方 设定SpringMVC的核心控制器bean

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //2.制作控制器类,等同于Servlet
    //2.1必须是一个spring管理的bean
    //2.2定义具体处理请求的方法
    //2.3设置当前方法的访问路径
    //2.4设置响应结果为json数据
    @Controller
    public class UserController {

    @RequestMapping("/save")
    @ResponseBody
    public String save(){
    System.out.println("user save ...");
    return "{'module':'springmvc'}";
    }
    }
  • 创建配置类

    1
    2
    3
    4
    5
    //3.定义配置类加载Controller对应的bean
    @Configuration
    @ComponentScan("com.itheima.controller")
    public class SpringMvcConfig {
    }
  • 创建Tomcat的Servlet容器配置类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //4.定义servlet容器的配置类
    public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
    //加载springMVC配置
    protected WebApplicationContext createServletApplicationContext() {
    //初始化WebApplicationContext对象
    AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
    //加载指定配置类
    ctx.register(SpringMvcConfig.class);
    return ctx;
    }

    //设置Tomcat接收的请求哪些归SpringMVC处理
    protected String[] getServletMappings() {
    return new String[]{"/"};
    }

    //设置spring相关配置
    protected WebApplicationContext createRootApplicationContext() {
    return null;
    }
    }
  • 第二种加载方式,重要

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ServletcontainersInitconfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}

protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}

protected String[] getServletMappings() {
return new String[]{"/"};
}
//乱码处理
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}

相关注解

1
2
3
4
5
6
7
8
@RequestMapping 设置当前控制器方法请求访问路径 位于SpringMVC控制器类或方法定义上方
@ResponseBody 设置当前控制器方法响应内容为当前返回值,无需解析 位于SpringMVC控制器类或方法定义上方
@Controller 定SpringMVC的核心控制器bean 位于SpringMVC控制器类定义上方
@ComponentScan 设置spring配置类扫描路径,用于加载使用注解格式定义的bean 位于类定义上方
@EnableWebMvc 开启json数据类型自动转换
@RequestParam 当形参和表单提交过来的元素名称不对应时
@ExceptionHandler 设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行 专用于异常处理器的上方
@Transactional 开启事务
  1. 相关方法的作用
  • AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化Web3.0容器的抽象类
  • AbstractDispatcherServletInitializer提供三个接口方法供用户实现
  • createRootApplicationContext()方法,如果创建Servlet容器时需要加载非SpringMVC对应的bean,使用当前方法进行,使用方式同createServletApplicationContext()
  • createServletApplicationContext()方法,创建Servlet容器时,加载SpringMVC对应的bean并放入WebApplicationContext对象范围中,而WebApplicationContext的作用范围为ServletContext范围,即整个web容器范围
  • ngetServletMappings()方法,设定SpringMVC对应的请求映射路径,设置为/表示拦截所有请求,任意请求都将转入到SpringMVC进行处理
  • createServletApplicationContext用来加载SpringMVC环境
  • createRootApplicationContext用来加载Spring环境

避免Spring错误的加载到bean

  • SpringMVC相关的bean(表现层bean)

  • Spring控制的bean

    1. 业务bean(service)
  1. 功能bean(DataSoure)
  • SpringMVC加载的bean对应的包都在com.xxx.controller包内

  • 方法

    1. 将spring加载bean的范围为com.xxx,排除掉controller包内的bean

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
            @configuration
      //@ComponentScan({"com.itheima.service","com.itheima.dao"})
      @Componentscan(value="com.itheima",
      excludeFilters =@ComponentScan.Filter(
      type = FilterType.ANNOTATION,
      classes =controllerfclass
      public class springconfig {
      }

      spring加载的bean设定扫面的范围为精准范围


      ### 其他需要注意的

      >- 当**使用ajax提交**时,可以指定contentType为json形式,那么在方法参数位置使用@RequestBody可以 直接接收集合数据而**无需使用POJO进行包装**

      >- SpringMVC的前端控制器 DispatcherServlet的url-pattern配置的是/,代表对所有的资源都进行过滤操作,通过以下配置放行静态资源

      ```xml
      <mvc:resources mapping="/js/**" location="/js/"/>

      <mvc:default-servlet-handler/>

    配置类配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  package com.itheima.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
//设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
//当访问/pages/????时候,从/pages目录下查找内容
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}

封装集合对象

1
2
3
4
5
6
7
8
9
//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
@RequestMapping("/listParam")
@ResponseBody
public String listParam(List<String> likes){
System.out.println("集合参数传递 likes ==> "+ likes);
return "{'module':'list param'}";
}
//SpringMVC将List看做是一个POJO对象来处理,将其创建一个对象并准备把前端的数据封装到对象中,但是List是一个接口无法创建对象,所以会报错
//:使用`@RequestParam`注解
  • JSON数据,用POJO类的话属性名对应上就行
1
2
3
4
5
6
7
//使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List<String> likes){
System.out.println("list common(json)参数传递 list ==> "+likes);
return "{'module':'list common for json param'}";
}

参数带@RequestBody的区别

  • 带注解的方法通常用于处理JSON格式的数据,不带注解的方法可以处理任何类型的请求参数,只要它们能够与pojo对象的属性名匹配

  • 带注解的方法从请求体中接收JSON数据并将其转为POJO对象,不带注解的从请求参数中获取数据,并将其绑定到POJO对象

  • 字符串的返回

QQ_1734395514145