SpringMVC

1.什么是SpringMVC?

SpringMVC是一种基于Java实现MVC模型的轻量级Web框架,

1.底层基于Spring (IOC和AOP)

IOC:
  1. 采用工厂模式(反射+读取配置文件)方式取代了之前是new创建对象的方式。
  2. 好处:解耦合。扩展性更强。

SPI机制:

1.SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件。

2.Java的SPI机制就是将一些类信息写在约定的文件中,然后由特定的类加载器加载解析文件获取资源。

3.Java SPI 基于 “接口编程+策略模式+配置文件(约定)”组合实现的动态加载机制。

4.SPI的运用场景:
场景 说明
数据库驱动 数据库驱动加载接口实现类的加载 JDBC加载不同类型数据库的驱动

日志门面SLF4J接口实现类加载 SLF4J加载不同提供商的日志实现类

Spring Spring中大量使用了SPI,比如:对servlet3.0规范对ServletContainerInitializer的实现、
自动类型转换Type Conversion SPI(Converter SPI、Formatter SPI)等

Dubbo Dubbo中也大量使用SPI的方式实现框架的扩展, 不过它对Java提供的原生SPI做了封装, 允许用户扩展实现Filter接口

SpringBoot SpringBoot基于SPI思想实现自动装配

2.封装了web三大组件(Servlet,Filter,Listener)

优点:
       使用简单,开发便捷(相比于Servlet)

       灵活性强

MVC模型:

MVC(Model View Controller):

  • Model(模型):负责封装应用的状态,并实现应用的功能。通常分为:数据模型、业务逻辑模型
  • View(视图):页面视图,用于展示数据
  • Controller(控制器):处理用户交互的调度器,用于根据用户需求处理程序逻辑

轻量级:与EJB(enterprice javabean)对比,依赖资源少,消耗的资源少。

Web框架:

 Web框架旨在帮助开发Web应用程序,包括Web管理,Web资产和Web [API](https://so.csdn.net/so/search?q=API&spm=1001.2101.3001.7020)。 因此,框架就是可以帮助您更快,更智能地构建应用程序的库。

SpringMVC是Web框架的一种。

2、组件及其作用

前端控制器(DispatcherServlet):接收请求,响应结果,相当于电脑的CPU;

处理器映射器(HandlerMapping):根据URL去查找处理器;

处理器(Handler):需要程序员去写代码处理逻辑;

处理器适配器(HandlerAdapter):把处理器包装成适配器,这样就可以支持多种类型的处理器,类比笔记本的适配器(适配器模式的应用);

视图解析器(ViewResovler):进行视图解析,将返回的字符串进行处理,可以解析成对应的页面。

3、工作原理

第一步:用户发起请求到前端控制器(DispatcherServlet);

第二步:前端控制器请求处理器映射器(HandlerMappering)去查找处理器(Handle,通过xml配置或者注解进行查找);

第三步:找到以后处理器映射器(HandlerMappering)像前端控制器返回执行链(HandlerExecutionChain);

第四步:前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)去执行处理器(Handler);

第五步:处理器适配器去执行Handler;

第六步:Handler执行完给处理器适配器返回ModelAndView;

第七步:处理器适配器向前端控制器返回ModelAndView;

第八步:前端控制器请求视图解析器(ViewResolver)去进行视图解析;

第九步:视图解析器像前端控制器返回View;

第十步:前端控制器对视图进行渲染;

第十一步:前端控制器向用户响应结果。

4.操作步骤

  1. 导入坐标(SpringMVC依赖、Servlet依赖)

  2. 创建SpringMVC控制器类(等同于Servlet)

  3. 初始化SpringMVC环境

  4. 初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC请求拦截的路径
    底层加载特定接口实现类MATEINFO Servilet文件夹的类获取全限定名反射创建对象

extends AbstractDispatcherServletInitializer
或者 extendsAbstractAnnotationConfigDispatcherServletInitializer

代码示例:

SpringMVC控制器类

@Controller
@RequestMapping("/role")
public class RoleController {
    @RequestMapping(value = "/save", method = RequestMethod.GET)
    @ResponseBody
    public String save(){
        System.out.println("RoleController save...");
        return "save success";
    }

    @RequestMapping(path = "/delete", method = RequestMethod.POST)
    @ResponseBody
    public String delete(){
        System.out.println("RoleController delete...");
        return "delete success";
    }
}

SpringMVC配置类

@Configuration
@ComponentScan("com.itheima.controller")
public class SpringmvcConfig {
}

Web容器配置类

  • 使用AbstractDispatcherServletInitializer的子类简化SpringMVC的容器配置类

    • 子类:AbstractAnnotationConfigDispatcherServletInitializer
//web容器配置类
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    //加载SpringMVC配置
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringmvcConfig.class};
    }

    //设置由springmvc控制器处理的请求映射路径
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};//SpringMVC控制器处理所有的请求
    }

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }
}

5.SpringMVC的请求处理

SpringMVC的请求处理介绍

SpringMVC主要应用在三层架构中的表现层(web层)。作用就是:

  1. 接收请求
  2. 业务处理(交给业务层)
  3. 响应数据

SpringMVC的请求处理可以分为两大类:

同步请求
  • 请求参数通常以url格式为主
GET :http://localhost:8080/save?username=itheima&password=123
POST :http//localhost:8080/save
       请求体:username=itheima&password=123
  • 特点:同步请求的响应内容会刷新整个网页
  • 响应:跳转页面

异步请求
  • 请求参数通常有:url格式、json格式
  • 特点:请求的响应内容只会让页页局部刷新
  • 响应:字符串数据、json格式数据

SpringMvc对请求和响应进行了封装:

  • 控制器类中的方法可以接收请求参数
  • 请求携带以下类型的数据时SpringMVC会自动接收,并在解析之后传递给方法进行使用

    1. 基本数据类型、String
    2. pojo类型
    3. 数组类型
    4. 集合类型
  • 使用方式:直接在方法上定义形参
@RequestMapping(value = "/login")
@ResponseBody
public String login(String username,String password){
    return "login success";
}
注意:方法上的形参名称必须要和请求参数名称保持一致

URL格式的GET请求: http://localhost:8080/login?username=itheima&password=123

6.SpringMVC的url格式请求参数

url格式的请求参数类型:

  1. 基本数据类型、String
    普通参数:请求参数与形参名称对应即可完成参数传递

  2. Pojo类型
    嵌套POJO参数:嵌套属性按照层次结构设定名称即可完成参数传递

                  举例:pojo类  private String name;
                               private int  age;
                               private Address  address(adress是一个实体类)
    
                        前端输入数据:name = 张三
                                    age  =18 
    
                                    address.province
                                    address.city
                                    即可完成封装
    
  1. 数组类型
    数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
              hobbies = 爬山
              hobbies = 游泳
    
  1. 集合类型
    请求参数名与形参集合对象名相同且请求参数为多个,使用 @RequestParam绑定参数关系
              public String listParam(@RequestParam List<String> likes){}
    


代码实例:
控制器类

@Controller
public class UserController {
    //普通参数:请求参数与形参名称对应即可完成参数传递
    @RequestMapping("/commonParam")
    @ResponseBody
    public String commonParam(String name ,int age){
        System.out.println("普通参数传递 name ==> "+name);
        System.out.println("普通参数传递 age ==> "+age);
        return "commonParam";
    }

    //POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
    @RequestMapping("/pojoParam")
    @ResponseBody
    public String pojoParam(User user){
        System.out.println("pojo参数传递 user ==> "+user);
        return "pojoParam";
    }

    //嵌套POJO参数:嵌套属性按照层次结构设定名称即可完成参数传递
    @RequestMapping("/pojoContainPojoParam")
    @ResponseBody
    public String pojoContainPojoParam(User user){
        System.out.println("pojo嵌套pojo参数传递 user ==> "+user);
        return "pojoContainPojoParam";
    }

    //数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
    @RequestMapping("/arrayParam")
    @ResponseBody
    public String arrayParam(String[] likes){
        System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes));
        return "arrayParam";
    }

    //集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
    @RequestMapping("/listParam")
    @ResponseBody
    public String listParam(@RequestParam List<String> likes){
        System.out.println("集合参数传递 likes ==> "+ likes);
        return "listParam";
    }
}

Pojo类

public class Address {
    private String province;//省份
    private String city;//城市

    @Override
    public String toString() {
        return "Address{" +
                "province='" + province + '\'' +
                ", city='" + city + '\'' +
                '}';
    }
    public String getProvince() {
        return province;
    }
    public void setProvince(String province) {
        this.province = province;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
}
public class User {
    private String name;
    private Integer age;
    public Address address;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address=" + address +
                '}';
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Address getAddress() {
        return address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
}

使用postman工具,测试请求参数:

  • 基本数据类型、String
@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(String name ,int age){
    System.out.println("普通参数传递 name ==> "+name);
    System.out.println("普通参数传递 age ==> "+age);
    return "commonParam";
}

Pojo类型

  • 请求参数名与方法形参对象属性名相同(定义POJO类型形参即可接收参数)
//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(User user){
    System.out.println("pojo参数传递 user ==> "+user);
    return "pojoParam";
}

嵌套POJO参数:请求参数名与形参对象属性名相同(按照对象层次结构关系即可接收嵌套POJO属性参数)

//嵌套POJO参数:嵌套属性按照层次结构设定名称即可完成参数传递
@RequestMapping("/pojoContainPojoParam")
@ResponseBody
public String pojoContainPojoParam(User user){
    System.out.println("pojo嵌套pojo参数传递 user ==> "+user);
    return "pojoContainPojoParam";
}

数组类型

  • 请求参数名与方法形参数组名相同且请求参数为多个(定义数组类型形参即可接收参数)
//数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
@RequestMapping("/arrayParam")
@ResponseBody
public String arrayParam(String[] likes){
    System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes));
    return "arrayParam";
}

集合类型

  • 请求参数名与形参集合对象名相同且请求参数为多个,使用@RequestParam绑定参数关系
//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List<String> likes){
    System.out.println("集合参数传递 likes ==> "+ likes);
    return "listParam";
}

7.SpringMVC的json格式请求参数

Json知识介绍

json格式数据:

  1. 对象 :{ }
  2. 数组 :[ ]

json格式请求参数常见类型:

1.json对象

User
{"name":"zs","age" : 18}

2.json数组

String[] 
["a","b","c"]

3.json数组(POJO)

List<User>
[{"name":"zs","age" : 18},{"name":"ls","age":19}]

java中的json转换工具:

  • FastJson
  • JackSon (SpringMVC底层使用)

SpringMVC接收json请求参数的步骤

1.导入坐标

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

2.开启json数据自动转换

//开启json数据类型自动转换
@EnableWebMvc

3.接收json数据:使用@RequestBody注解把json数据映射到方法形参上

public String pojoParamForJson(@RequestBody User user)

获取json格式的请求参数

代码示例:

  • SpringMVC配置类
@Configuration
@ComponentScan("com.itheima.controller")
//开启json数据类型自动转换
@EnableWebMvc //@EnableWebMvc注解整合了多个功能,此处仅使用json数据进行自动类型转换
public class SpringmvcConfig {
}

SpringMVC控制器类

@Controller
public class UserController {
    //POJO参数:json格式
    //1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
    //2.使用@RequestBody注解将外部传递的json数据映射到形参的实体类对象中,要求属性名称一一对应
    @RequestMapping("/pojoParamForJson")
    @ResponseBody
    public String pojoParamForJson(@RequestBody User user){
        System.out.println("pojo(json)参数传递 user ==> "+user);
        return "pojoParamForJson";
    }

    //集合参数:json格式
    //1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
    //2.使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
    @RequestMapping("/listParamForJson")
    @ResponseBody
    public String listParamForJson(@RequestBody List<String> likes){
        System.out.println("list common(json)参数传递 list ==> "+likes);
        return "listParamForJson";
    }

    //集合参数:json格式
    //1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
    //2.使用@RequestBody注解将外部传递的json数组数据映射到形参的保存实体类对象的集合对象中,要求属性名称一一对应
    @RequestMapping("/listPojoParamForJson")
    @ResponseBody
    public String listPojoParamForJson(@RequestBody List<User> list){
        System.out.println("list pojo(json)参数传递 list ==> "+list);
        return "listPojoParamForJson";
    }
}

使用postman工具,测试请求参数:

  • POJO参数:json数据与形参对象属性名相同 (定义POJO类型形参即可接收参数)
@RequestMapping("/pojoParamForJson")
@ResponseBody
public String pojoParamForJson(@RequestBody User user){
    System.out.println("pojo(json)参数传递 user ==> "+user);
    return "pojoParamForJson";
}
@RequestMapping("/listPojoParamForJson")
@ResponseBody
public String listPojoParamForJson(@RequestBody List<User> list){
    System.out.println("list pojo(json)参数传递 list ==> "+list);
    return "listPojoParamForJson";
}

关键API总结

  • url格式请求参数

  • json格式请求参数

    • @EnableWebMvc //开启webmvc功能(功能之一: 自动实现json和pojo转换)
    • @RequestBody //在参数前面添加,用于接收json格式参数映射到pojo上

8.SpringMVC的特殊情况请求参数

1.当请求的参数名和目标方法中的形参名不一致时, 使用

            @RequestParam注解,建立请求参数名与形参名称之间的关系

            public String commonParam(@RequestParam("name") String username ,

                          @RequestParam("age") int userage)

2.post请求乱码解决 (get请求:Tomcat8版本开始已解决)

<br />

在ServletContainersInitConfig配置类中进行配置即可
@Override
protected Filter[] getServletFilters() {
//spring封装的过滤器, 拦截所有的请求,如果是post请求,就将编码修改为指定编码
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding(“UTF-8”);
return new Filter[]{filter};
}

             3.日期类型数据基于系统不同格式也不尽相同

             使用注解: @DateTimeFormat
             根据请求传入的格式设置对应的pattern
             public String dateParam(
             Date date1,
             @DateTimeFormat(pattern = "yyyy-MM-dd")   Date date2,
             @DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss")   Date date3)

9.SpringMVC的响应处理

使响应的内容当作响应体使用 @ResponseBody 注解

                可以响应 String ,pojo实体类 , list集合

                特殊://返回值为String类型,设置返回值为页面名称,即可实现页面跳转
                    //前后端分离后不常用(了解)

10.SpringMVC的RESTful风格

<br />

介绍 :一种网络资源的访问风格,定义了网络资源的访问方式

            REST风格访问路径:

                http ://localhost/user/1

                可以具有多个含义:
                既可以是查询,也可以是删除,也可以是修改,也可以是添加(别人根本就不知道开发者在干嘛)

            RESTful风格请求

        当同一个请求路径,想访问不同的资源是,restful风格依据发送的请求类型来区别:

        添加:
        @RequestMapping(value = "/rest",method = RequestMethod.POST)
        修改:
        @RequestMapping(value = "/rest",method = RequestMethod.PUT)
        删除:
        @RequestMapping(value = "/rest",method = RequestMethod.DELETE)
        查询:
        @RequestMapping(value = "/rest",method = RequestMethod.GET)

当使用的请求方式需要带参数,可以使用参数表达式,并在获取的方法形参列表添加一个注解

            .@PathVariable

        一个参数:
          @RequestMapping(value = "/rest/{id}",method = RequestMethod.DELETE)
                            ||
                        ||
                        \/
             public String deleteById(@PathVariable Integer id){

两个参数:

        @RequestMapping(value = "/rest/{page}/{pageSize}",method = RequestMethod.GET)

                            ||
                            ||
                            \/
        public List<User> findByPage(@PathVariable Integer page, @PathVariable Integer pageSize){

restful 组合注解优化

@RestController= @Controller + @ResponceBody

                @GetMapping("/rest") = @RequestMapping(value = "/rest",method = RequestMethod.GET)

                以此类推...........

综合案例 vue项目创建步骤

html页面

                1导入css ,js库,elementui.....
                2.引入css样式,vue组件

                <link rel="stylesheet" href="../plugins/elementui/index.css">
                <link rel="stylesheet" href="../plugins/font-awesome/css/font-awesome.min.css">
                <link rel="stylesheet" href="../css/style.css">
                <!-- 引入组件库 -->
                    <script src="../js/vue.js"></script>
                    <script src="../plugins/elementui/index.js"></script>
                    <script type="text/javascript" src="../js/jquery.min.js"></script>
                    <script src="../js/axios-0.18.0.js"></script>

                    3.<body>区域写试图  <div class="app"><div/>

                    4.div外写scrip脚本

                    <script>
                    //vue对象
                        new Vue({
                    //绑定视图
                        el:'#app',
                    //页面数据源
                        data:{},
                    //函数
                        methods:{}
                        })

                    </script>

                    5.映入elment ui需要的内容进行修改

SSM框架整合流程

SSM整合:

  1. 搭建Spring环境
    步骤:

       1. 导入坐标:spring-webmvc
    
    ```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">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.itheima</groupId>
      <artifactId>springmvc_day02-ssm</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>war</packaging>
    
      <!-- 依赖管理 -->
      <dependencies>
          <!-- SpringMVC(底层依赖Spring)-->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-webmvc</artifactId>
              <version>5.2.10.RELEASE</version>
          </dependency>
    
      </dependencies>
    </project>
    

    ```




在spring-webmvc依赖中包含了:spring-context

      2. 编写Spring配置类(注解开发)

     ```java
     /* Spring IoC容器(父容器)
         1. 管理除Controller包之外的所有bean
         2. spring的组件扫描 : 扫描controller包之外的其他包
             1). 方案一: 一个个配置,就是不配置controller包
             2). 方案二: 全扫描,排除controller包
                 ComponentScan
                     I. value : 要扫描的包
                     II. excludeFilters : 排除不扫描 Controller和 RestController注解
                             a. type : 要排除的类型 (注解)
                             b. classes : 要排除的类
     */
     /*@ComponentScan(value = "com.itheima",
             excludeFilters = {
                    @ComponentScan.Filter(
                            type = FilterType.ANNOTATION,
                            classes = {Controller.class, RestController.class}
                            )
             }
     )*/
     //Spring配置类 (添加到IoC容器中)
     @Configuration
     @ComponentScan({"com.itheima.service"}) //扫描service层包
     public class SpringConfig {
     }
 加载MybatisConfig配置类

 ```java
 //Mybatis配置类
 public class MybatisConfig {
     @Bean
     public SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource ds){
         SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
         //设置pojo的包扫描
         factoryBean.setTypeAliasesPackage("com.itheima.domain");
         //设置连接池
         factoryBean.setDataSource(ds);
         return factoryBean;
     }

     @Bean
     public MapperScannerConfigurer mapperScannerConfigurer(){
         MapperScannerConfigurer msc = new MapperScannerConfigurer();
         //设置dao层的接口扫描
         msc.setBasePackage("com.itheima.dao");
         return msc;
     }
 }
 ```

  加载JdbcConfig配置类

 ```java
 //配置:连接池、事务管理器
 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 dataSource = new DruidDataSource();
         dataSource.setDriverClassName(driver);
         dataSource.setUrl(url);
         dataSource.setUsername(username);
         dataSource.setPassword(password);
         return dataSource;
     }

     //设置事务管理器 (声明式事务)
     @Bean
     public PlatformTransactionManager transactionManager(DataSource dataSource){
         //PlatformTransactionManager是DataSourceTransactionManager的父接口
         DataSourceTransactionManager dstm = new DataSourceTransactionManager();
         dstm.setDataSource(dataSource);
         return dstm;
     }
 }
 ```

  加载service层的bean到IOC容器
  开启事务管理支持
  加载外部资源配置文件
  1. Spring和Mybatis整合 步骤:

    1. 导入坐标:mysql、mybatis、druid、mybatis-spring、spring-jdbc
      1. 编写配置类:MybatisConfig、JdbcConfig MybatisConfig:代替mybatis-config.xml 封装SqlSessionFactory、SqlSession 指定要扫描的dao层 配置pojo类别名 JdbcConfig:连接池、声明式事务 @EnableTransactionManagement
      2. 编写dao层
      3. 编写service 添加 @Service,表示业务类由SpringIoC容器管理 添加BookDao依赖注入
  2. Spring和SpringMVC整合

    • 步骤:
      1. 导入坐标:servlet、jackson
      2. 编写配置类:SpringMVC配置类、Web容器配置类
    • SpringMVC配置类:
      • 加载controller层的bean到ioc容器
      • 开启json和javabean之间的互相转换
    • Web容器配置类:Tomcat启动时,基于SPI机制,会自动加载
      • 加载SpringConfig配置类
      • 加载SpringmvcConfig配置
      • 配置请求路径(所有请求)
      • 处理中文乱码
      1. 编写Controller
      2. 使用浏览器/postman测试 ```