Day05--SpringMvc

SpringMVC简介

SpringMvc概述

1. SpringMVC是一种基于Java实现MVC模型的轻量级Web框架
1). 底层基于Spring
2). 封装了web三大组件(Servlet,Filter,Listener)
2. 优点
1). 使用简单,开发便捷(相比于Servlet)
2). 灵活性强

SpringMVC相关依赖

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

初始化SpringMVC环境(同Spring)

//springmvc配置类,本质上还是一个spring配置类
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringMvcConfig {
}

创建SpringMVC控制器类(等同于Servlet功能)

//定义表现层控制器bean
@Controller
public class UserController {

    //设置映射路径为/save,即外部访问路径
    @RequestMapping("/save")
    //设置当前操作返回结果为字符串
    @ResponseBody
    public String save(){
        System.out.println("user save ...");
        return "hello";
    }
}

初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC请求拦截的路径

//AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化Web3.0容器的抽象类
//web容器配置类
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
    //加载springmvc配置类,产生springmvc容器(本质还是spring容器)
    protected WebApplicationContext createServletApplicationContext() {
        //初始化WebApplicationContext对象
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        //加载指定配置类
        ctx.register(SpringMvcConfig.class);
        return ctx;
    }

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

    //加载spring配置类
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }
}

核心API

@Controller

1. 类型类注解
2. 位置:SpringMVC控制器类定义上方
3. 作用:设定SpringMVC的核心控制器bean
4. 范例

        @Controller
        public class UserController {
        }

@RequestMapping

1. 类型:方法注解
2. 位置:SpringMVC控制器方法定义上方
3. 作用:设置当前控制器方法请求访问路径
说白了就是建立请求路径与处理器方法之间的映射关系
4. 范例:

@RequestMapping("/save")
public void save(){
	System.out.println("user save ...");
}

@ResponseBody

1. 类型:方法注解
2. 位置:SpringMVC控制器方法定义上方
3. 作用:设置当前控制器方法响应体内容为当前返回值,无需解析
说白了,就是将方法返回值序列化成字符串给前端返回;
4. 范例

        @RequestMapping("/save")
        @ResponseBody
        public String save(){
            System.out.println("user save ...");
            return "hello";
        }

基本案例流程分析

# 启动服务器初始化过程
0. tomcat -> ServletContainersInitConfig -> SpringMvcConfig -> UserController
						
1. tomcat的启动执时,根据SPI机制加载ServletContainersInitConfig1). spring-web.jar下有META-INF/services/javax.servlet.ServletContainerInitializer文件 
	2). 此文件中配置实现类 org.springframework.web.SpringServletContainerInitializer
        3). 此类会被tomcat所加载(SPI机制),此类上的有个配置@HandlesTypes({WebApplicationInitializer.class}) 
        4). 此接口WebApplicationInitializer的所有实现类都会被加载封装到set集合中,通过onStartup方法传入;
        	(SpringServletContainerInitializer的onStartup)
        5). 而我们入门案例中的ServletContainersInitConfig类就是WebApplicationInitializer实现类,所以也会被运行
2. ServletContainersInitConfig类的方法会被运行
		1). createServletApplicationContext方法运行,加载springmvc配置类
		2). getServletMappings方法运行,DispatcherServlet类设置访问路径为/ (表示拦截所有)
3. SpringMvcConfig类配置的注解生效
		1). @ComponentScan("com.itheima.controller")
		2). springmvc底层开始扫描	com.itheima.controller包
4. UserController类生效
		1). @Controller
			表示此bean会添加到springmvc的ioc容器
		2).  @RequestMapping("/save")
        	设置save方法的访问路径为 /save
        3). @ResponseBody
        	方法的的返回值String将会通过响应体返回给前端
 总之,springmvc通过spi机制调用    SpringServletContainerInitializer中的onstart方法来完成IOC容器以及核心调度器初始化的操作;   	
# 问题:
1. 入门案例是一个web项目,为何不写web.xml文件?
		SPI机制: ServletContainerInitializer
2. 入门案例为何不写Servlet?
		springMVC底层封装了DispatcherServlet,它拦截所有请求,然后分发给Controller.
       

单次请求过程

0. 浏览器(前端) -> (后端)tomcat -> DispatcherServlet -> UserController.save
1. 前端发送请求 http://localhost:8080/save
2. http://localhost:8080会找到tomcat(web容器-》servlet容器)
3. tomcat接收到请求,发现spingmvc中有个DispatcherServlet的拦截路径为/,所以就将请求交给DispatcherServlet,service方法会运行
4. DispatcherServlet会找到/save对应的控制器方法UserController.save方法,然后调用此方法
5. UserController.save方法运行之后,String类型的返回值hello,通过响应体返回给前端

ServletContainersInitConfig的常用写法

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
	
    //加载springmvc配置的
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }
    //设置由springmvc控制器处理的请求映射路径
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
    //加载spring配置类
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }
}

RequestMapping注解

作用: RequestMapping 注解,用于建立请求路径与方法的对应关系。

2.1 编写位置

# 编写位置:
1. 类上:
		窄化路径,访问此类中的方法时,必须加上类上的路径
2. 方法:
		建立路径与方法的对应关系
@Controller
//类上方配置的请求映射与方法上面配置的请求映射连接在一起,形成完整的请求映射路径
@RequestMapping("/user")
public class UserController {
    //请求路径映射
    @RequestMapping("/save")
    @ResponseBody
    public String save(){
        System.out.println("user save ...");
        return "hello";
    }
    //请求路径映射
    @RequestMapping("/delete")
    @ResponseBody
    public String delete(){
        System.out.println("user delete ...");
        return "hello";
    }

}

2.2 常用属性

# @RequestMapping注解常用属性
1. value或者path: 用来指定虚拟路径,value=可以省略 
2. method: 用来限定请求的方式   (restful风格)
		1). 不写,默认什么请求方式都可以
		2). 写了,指定了请求方式,如果不匹配就会响应405状态码(错误)


@Controller
@RequestMapping("/role")
public class RoleController {

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

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

请求

# SpringMVC的请求处理可以分为两大类: 
这里说的同步请求和异步请求指的是前端
1. 同步请求
	0). 特点: 同步请求的响应内容会刷新整个网页
	1). url格式的请求参数
	2). 响应: 请求转发
	
2. 异步请求 (主流!!!)
	0). 特点: 响应内容只会让网页局部刷新
		ajax/json (封装库,框架 axios/vue...)
	1). 请求参数
		url格式 name=value&name=value...
		json格式
	2). 响应
		字符串
		json格式
# SpringMvc对请求和响应进行了封装	
1. 我们的控制器方法可以接收请求参数
2. 如果请求携带以下类型的数据,SpringMVC会自动帮我们接收,并且解析之后传递给方法进行使用
3. 使用方式: 直接定义方法形参
4. 注意: 方法上的形参名称必须要和请求参数名称保持一致
    1).基本数据类型和string
    2).pojo类型 
    3).数组类型 
    4).集合类型 

@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 "hello";
    }

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

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

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

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

获取json格式的请求参数

# json格式数据
1. 对象  { }
2. 数组  [ ] 
# json格式请求参数常见类型
1. json数组 
		String [] / int[]
		["a","b","c"]
2. json对象(POJO)
		User
		{"name":"zs","age" : 18}
3. json数组(POJO) 
		List<User>
		[{"name":"zs","age" : 18},{"name":"ls","age":19}]
# java中的json转换工具
1. fastJson ( alibaba的 ) 
	1). json格式字符串变成 pojo对象
	2). pojo对象变成json格式字符串
2. JackSon (springMVC底层使用)	
3. gson
# web阶段封装的一个工具类 BaseController
1. 接收json格式的请求参数 变成 pojo
2. 将pojo的响应数据 变成 json格式字符串

jsckson依赖

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

开启自动抓换JSON的支持

@Configuration
@ComponentScan("com.itheima.controller")
//开启json数据类型自动转换
//@EnableWebMvc注解功能强大,该注解整合了多个功能,此处仅使用其中一部分功能,即json数据进行自动类型转换
@EnableWebMvc
public class SpringMvcConfig {
}

设置接受JSON数据

    @RequestMapping("/listPojoParamForJson")
    @ResponseBody
    public String listPojoParamForJson(@RequestBody List<User> list){
        System.out.println("list pojo(json)参数传递 list ==> "+list);
        return "{'module':'list pojo for json param'}";
    }

核心代码

 //集合参数: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 "{'module':'list common for json param'}";
    }

    //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 "{'module':'pojo for json param'}";
    }

    //集合参数: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 "{'module':'list pojo for json param'}";
    }

核心API总结

@RequestBody与@RequestParam区别


1. 区别
		@RequestParam用于接收url地址传参,表单传参【application/x-www-form-urlencoded】
		@RequestBody用于接收json数据【application/json】
2. 应用
		后期开发中,发送json格式数据为主,@RequestBody应用较广
		如果发送非json格式数据,选用@RequestParam接收请求参数

json格式请求参数

1. @RequestParam
		接收集合类型的参数
1. 记得导入jackSon工具包(实现json和pojo之间的数据转换)
2. @EnableWebMvc
		开启webmvc功能(功能之一: 自动实现json和pojo转换)
3. @RequestBody
		在参数前面添加,用于接收json格式参数映射到pojo上

请求参数名称不一致

 # @RequestParam
1. value : 指定前端的属性名映射到某个参数上
       使用前提: 形参名跟前端name属性名不一致
   
2. required:用于指定此参数是否必传
    true: (默认)表示必须要传,只要前端声明有name属性,不填属性值,也是有的
    
3. defaultValue:如果前端此参数值没有设置,这里参数会指定一个默认值。
4.   //普通参数:请求参数名与形参名不同时,使用@RequestParam注解关联请求参数名称与形参名称之间的关系
    @RequestMapping("/commonParamDifferentName")
    @ResponseBody
    public String commonParamDifferentName(@RequestParam("name") String userName , int age){
        System.out.println("普通参数传递 userName ==> "+userName);
        System.out.println("普通参数传递 age ==> "+age);
        return "{'module':'common param different name'}";
    }

编码过滤器

     //post请求乱码处理
    @Override
    protected Filter[] getServletFilters() {
        //spring封装的过滤器, 拦截所有的请求,如果是post请求,就将编码修改为指定编码
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }

日期处理

	//日期参数
    //使用@DateTimeFormat注解设置日期类型数据格式,默认格式yyyy/MM/dd
    @RequestMapping("/dataParam")
    @ResponseBody
    public String dataParam(Date date,
                            @DateTimeFormat(pattern="yyyy-MM-dd") Date date1,
                            @DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2){
        System.out.println("参数传递 date ==> "+date);
        System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1);
        System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2);
        return "{'module':'data param'}";
    }

响应

SpringMVC对响应的封装可以分为以下两类

  1. 响应页面
    用于同步请求,了解即可
    2. 响应数据
    1). 文本数据
    2). json数据(常用)

核心API

@ResponseBody

  1. 类型:方法注解|方法返回参数之上
  2. 位置:SpringMVC控制器方法定义上方
  3. 作用:设置当前控制器返回值作为响应体
  4. 只要配置好对应的环境 (需要导入jackson, 必须@EnableWebMvc)
    那么springmvc会自动将javabean返回值转成json格式字符串

示例代码

 @RequestMapping("/resp")
    @ResponseBody
    public User responsebody(@RequestBody User user){
        System.out.println(user);
        user.setName("小李");
           return  user;
    }

Springmvc对Restful风格的支持

Restfu

- RestRepresentational State Transfer) 直接翻译的意思是"表现层的状态转化"。  

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

- Restful是按照Rest风格访问网络资源

  - 传统风格访问路径
     http://localhost:80/user/get?id=1
     http://localhost/user/delete?id=1

- Rest风格访问路径
   http://localhost/user/1

  - 强调的点有2点:
    - 路径即资源(路径中只能使用名词,不能使用动词)
    - 用请求方式表达对资源的操纵行为
      - 比如:http://localhost/user/1 请求方式:GET   表示查询id=1的用户信息
 # 含义可以多个:    既可以是查询,也可以是删除,也可以是修改,也可以是添加    别人根本就不知道开发者在干嘛
 优点
 隐藏资源的访问行为,通过地址无法得知做的是何种操作(安全)
 书写简化

Rest行为约定方式

Restful 使用URL定位资源,用HTTP请求方式(GET,POST,PUT,DELETE)描述操作

 GET(查询) http://localhost/user GET
 POST(保存) http://localhost/user POST
 PUT(更新) http://localhost/user PUT
 DELETE(删除) http://localhost/user DELETE

注意:上述行为是约定方式,约定不是硬性规范,可以打破,所以称Rest风格,而不是Rest规范

Restful开发入门

@Controller
public class RestController {

    @RequestMapping(value = "/rest",method = RequestMethod.GET)
    @ResponseBody
    public String demo01(){
        System.out.println("findAll");
        return "findAll";
    }

    @RequestMapping(value = "/rest/{id}",method = RequestMethod.GET)
    @ResponseBody
    public String demo11(@PathVariable Integer id){
        System.out.println("findById : " + id);
        return "findById";
    }

    @RequestMapping(value = "/rest/{page}/{pageSize}",method = RequestMethod.GET)
    @ResponseBody
    public String demo12(@PathVariable Integer page,@PathVariable Integer pageSize){
        System.out.println("findByPage : " + page + "," + pageSize);
        return "findByPage";
    }

    @RequestMapping(value = "/rest",method = RequestMethod.DELETE)
    @ResponseBody
    public String demo02(){
        System.out.println("deleteAll");
        return "deleteAll";
    }
    @RequestMapping(value = "/rest/{id}",method = RequestMethod.DELETE)
    @ResponseBody
    public String demo21(@PathVariable Integer id){
        System.out.println("deleteById : " + id);
        return "deleteById";
    }

    @RequestMapping(value = "/rest",method = RequestMethod.POST)
    @ResponseBody
    public String demo03(@RequestBody User user){
        System.out.println("add: " + user);
        return "add";
    }


    @RequestMapping(value = "/rest",method = RequestMethod.PUT)
    @ResponseBody
    public String demo04(){
        System.out.println("update");
        return "update";
    }
}

Restful快速开发

/*
    复合注解 : A和B注解作为C的元注解, 那么C= A+B

    @RestController = @Controller + @ResponseBody
 */
//@Controller
//@ResponseBody // 表示每个方法响应数据都直接走响应体
@RestController
@RequestMapping("/rest")
public class RestfulController {

//    @RequestMapping(value = "/rest",method = RequestMethod.GET)
//    @GetMapping(value = "/rest")
    @GetMapping
    public String demo01(){
        System.out.println("findAll");
        return "findAll";
    }

//    @RequestMapping(value = "/rest/{id}",method = RequestMethod.GET)
    @GetMapping("/{id}")
    public String demo11(@PathVariable Integer id){
        System.out.println("findById : " + id);
        return "findById";
    }

//    @RequestMapping(value = "/rest/{page}/{pageSize}",method = RequestMethod.GET)
    @GetMapping("/{page}/{pageSize}")
    public String demo12(@PathVariable Integer page,@PathVariable Integer pageSize){
        System.out.println("findByPage : " + page + "," + pageSize);
        return "findByPage";
    }

//    @RequestMapping(value = "/rest",method = RequestMethod.DELETE)
    @DeleteMapping
    public String demo02(){
        System.out.println("deleteAll");
        return "deleteAll";
    }
//    @RequestMapping(value = "/rest/{id}",method = RequestMethod.DELETE)
    @DeleteMapping("/{id}")
    public String demo21(@PathVariable Integer id){
        System.out.println("deleteById : " + id);
        return "deleteById";
    }


//    @RequestMapping(value = "/rest",method = RequestMethod.POST)
    @PostMapping
    public String demo03(@RequestBody User user){
        System.out.println("add: " + user);
        return "add";
    }


//    @RequestMapping(value = "/rest",method = RequestMethod.PUT)
    @PutMapping
    public String demo04(){
        System.out.println("update");
        return "update";
    }
}

总结

1.三层架构与MVC架构的关系?

三层架构包含数据访问层、业务逻辑层、web层(servlet html model);
MVC架构是对三层架构中的web层的再细粒度划分:解耦 提高代码复用 关注点分离;

2.sringmvc启动流程?

1.tomcat启动时,底层根据java提供的SPI机制,会自动加载spring-web-5.2.10.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer文件中的类:SpringServletContainerInitializer
并调用onStartup方法,该方法会收集当前项目中所有实现WebApplicationInitializer接口的类,并封装到set集合中农,然后注入onStartup方法中(SPI)
2.SpringServletContainerInitializer下的onStartup方法执行时,会循环调用一切实现WebApplicationInitializer接口的对象中的onStartup方法
3.我们工程中ServletContainersInitConfig最后也实现了WebApplicationInitializer,所以它的onStartup也会被调用,该方法会间接调用初始化IOC容器的方法和核心调度器DispatchServlet,并设置拦截规则“/”;

3.springmvc访问流程?

1.前端(浏览器)发送请求到后台,被tomcat接收
2.tomcat调用DispatchServlet核心调度器处理当前的请求;
3.DispatchServlet会根据请求的url地址找具体的处理器方法,并调用
4.处理器方法执行完毕,返回的数据被DispatchServlet响应给前端

4.springmvc请求相关的注解有哪些?

@ReqeustMapping 建立请求地址与处理器方法之间的关系,作用在类和方法之上;
	属性:
		value或者path:指定请求路径
		method:指定请求方法 get delete put post等
有4中衍生注解:
	@GetMapping  @DeleteMapping  @PutMapping @PostMapping

@Controller  
@RestController=@Controller  + @Responbody

关于参数处理的注解:
@ReqeustParam:解决请求参数与方法入参不一致的情况
	属性:
		value:指定请求参数名称
		required: 默认是true,定义是否必须传入;
		defaultValue:设置默认值
@RequestBoy:作用是接收前端ajax发送的json格式数据,并调用jackson工具自动实现json转java对象的功能	
			注解作用在方法的入参之上;
@DateTimeFormat(pattern="日志表达式")
要想使用springmvc的这些扩展功能,前提是开启:@EnalbeWebMvc
如何接收resetfull路径中的参数?
	使用@PathVariable("指定路径参数的名称")

响应数据:
@ResponseBody:
	特点:作用方法之上或者方法的返回值之上
	作用:如果方法的返回值是基本类型+string,则直接返回
		 如果方法的返回值是一些负载的pojo


		

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值