牛啊!终于有人把主流服务层框架SpringMVC讲明白了
SpringMVC简介
首先我们先来简单了解一下SpringMVC: SpringMVC是一种基于Java实现MVC模型的轻量级Web框架 SpringMVC致力于服务层,同Servlet一样应用于服务层,用于服务层开发 SpringMVC隶属于Spring,同样具有简化代码,使用简单,开发便捷,灵活性强的优点 SpringMVC入门案例
在未学习SpringMVC之前,我们的服务端开发通常采用Servlet: package com.itheima.web.servlet.old; import com.alibaba.fastjson.JSON; import com.itheima.pojo.Brand; import com.itheima.service.BrandService; import com.itheima.service.impl.BrandServiceImpl; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.util.List; //@WebServlet("/addServlet") public class AddServlet extends HttpServlet { private BrandService brandService = new BrandServiceImpl(); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1. 接收品牌数据 BufferedReader br = request.getReader(); String params = br.readLine();//json字符串 //转为Brand对象 Brand brand = JSON.parseObject(params, Brand.class); //2. 调用service添加 brandService.add(brand); //3. 响应成功的标识 response.getWriter().write("success"); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
我们可以注意到其过程非常繁琐,因为我们需要获取参数并进行类型转换,包括添加至Service等过程
但是SpringMVC秉承着简化代码的原则,将大部分内容转化为Java代码进行封装,大大减少了繁琐的过程
接下来我们来介绍SpringMVC版: 导入jar包 <?xml version="1.0" encoding="UTF-8"?> 4.0.0 com.itheima springmvc_01_quickstart 1.0-SNAPSHOT war javax.servlet javax.servlet-api 3.1.0 provided org.springframework spring-webmvc 5.2.10.RELEASE org.apache.tomcat.maven tomcat7-maven-plugin 2.1 80 / 创建SpringMVC控制类(等同于Servlet类) package com.itheima.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; //定义表现层控制器bean @Controller public class UserController { //设置映射路径为/save,即外部访问路径 @RequestMapping("/save") //设置当前操作返回结果为指定json数据(本质上是一个字符串信息) @ResponseBody public String save(){ System.out.println("user save ..."); return "{"info":"springmvc"}"; } //设置映射路径为/delete,即外部访问路径 @RequestMapping("/delete") @ResponseBody public String delete(){ System.out.println("user save ..."); return "{"info":"springmvc"}"; } } 初始化SpringMVC环境(同Spring一样创建Config配置Java类) package com.itheima.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; //springmvc配置类,本质上还是一个spring配置类 @Configuration @ComponentScan("com.itheima.controller") public class SpringMvcConfig { } 初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC技术处理的请求 /* 我们服务层的实际操作都是放置于Servlet容器中 我们配置的SpringMVC和Spring环境都是用于服务层,所以我们需要把相关Config加载仅Servlet容器中 */ package com.itheima.config; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer; // web容器配置类 // AbstractDispatcherServletInitializer是SpringMVC为我们设置好的类,继承并实现相关方法即可 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; } }
我们对上述新的内容进行解析: @Controller 名称:@Controller 类型:类注解 位置:SpringMVC控制类定义上方 作用:设定SpringMVC的核心控制器Bean @RequestMapping 名称:@RequestMapping 类型:方法注解 位置:SpringMVC控制器方法定义上方 作用:设置当前控制器方法请求访问路径 相关属性:value(请求访问路径) @ResponseBody 名称:@ResponseBody 类型:方法注释 位置:SpringMVC控制器方法定义上方 作用:设置当前控制器方法响应内容为当前返回值,无需解析 AbstractDispatcherServletInitializer类 AbstractDispatcherServletInitializer是SpringMVC提供的快速初始化Web3.0容器的抽象类 AbstractDispatcherServletInitializer提供三个接口方法供用户实现 createServletApplicationContext方法用于创建Servlet容器时,加载SpringMVC对应的Bean并放入 AnnotationConfigWebApplicationContext的作用范围对应整个Web容器范围,必须使用WebApplicationcontext类型
最后我们总结一下上述操作的出现频率: 一次性工作创建工程,设置服务器,加载工程导入坐标创建Web容器启动类,加载SpringMVC配置,并设置SpringMVC请求拦截路径SpringMVC核心配置类(设置配置类,扫描controller包,加载Controller控制器Bean) 常态工作定义处理请求的控制类定义处理请求的操作方法,并设置映射路径(@RequestMapper)与返回Json数据(@ResponseBody) SpringMVC工作流程
在分析SpringMVC工作流程前,我们需要知道服务层是由下面的框架组成的:
启动服务器初始化过程: 服务器启动,执行ServletContainersInitConfig类,初始化Web容器 执行createServletApplicationContext方法,创建了WebApplicationContext对象 加载SpringMvcConfig 执行@ComponentScan加载对应的bean 加载UserController,每个@RequestMapping的名称对应一个具体的方法 执行getServletMappings方法,定义所有的请求都通过SpringMVC
单次请求过程: 发送请求localhost/save Web容器发现所有请求都经过SpirngMVC,将请求交给SpringMVC处理 解析请求路径/save 由/save匹配执行对应的方法save() 执行save() 检测到有@ResponseBody直接将save()方法的返回值作为响应求体返回给请求方 SpringMVC加载控制
在学习SpringMVC之后,我们的Bean的范围逐渐变大: SpringMVC相关bean(表现层bean) Spring相关bean(业务层Service,功能DataSource等)
但是我们在使用时,需要区分相关bean的导入路径: SpringMVC加载的bean对应的包均在com.itheima.controller包内 Spring加载的bean却包含有多个文件夹
因而我们给出两种方法来解决Spring的扫描问题: Spring加载的bean设定范围为com.itheima,并排除掉controller包内的bean package com.itheima.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.stereotype.Controller; @Configuration /* @ComponentScan注解设置扫描范围 @ComponentScan中包含有value,excludeFilters属性 value:用于控制扫描范围 excludeFilters:用于控制排除范围,需要采用@ComponentScan.Filter过滤器 type:设置排除规则,当前使用按照bean定义时的注解类型进行排除 classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean */ @ComponentScan(value="com.itheima", excludeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, classes = Controller.class ) ) public class SpringConfig { } /* 这里做一个小补充内容: @ComponentScan中除了excludeFilters,还包括有includeFilters includeFilters:加载指定的bean,需要指定类型(type)和具体项(classes) */ Spring加载的bean设定范围为精准范围,例如service包,dao包等 package com.itheima.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.stereotype.Controller; @Configuration @ComponentScan({"com.itheima.service","com.itheima.dao"}) public class SpringConfig { } Servlet容器简化写法
我们的Servlet容器中可以定义Spring和SpringMVC的配置文件 package com.itheima.config; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer; public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { // 配置SpringMVC配置文件 protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; } // 配置Spring配置文件 protected WebApplicationContext createRootApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringConfig.class); return ctx; } // 配置拦截路径 protected String[] getServletMappings() { return new String[]{"/"}; } } 我们可以注意到:
Spring和SpringMVC导入方法中均采用AnnotationConfigWebApplicationContext来创建对象
两者之间的区别仅仅是class包的不同
Spring给了我们一种新的继承类用于简化开发: package com.itheima.config; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer; //web配置类简化开发,仅设置配置类类名即可 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[]{"/"}; } } 注意:
AbstractAnnotationConfigDispatcherServletInitializer是createServletApplicationContext的继承类
我们同样继承它的三个方法,但这次我们只需要在里面标明相关类和路径即可 常用工具推荐Postman
在我们的SpringMVC中岔开一个话题: 关于我们的网页调试的复杂性
我们在一个网页开发中,会不断的调试网页,通过各种路径反复查询或者采用不同的访问方式(GET/POST)
如果我们采用正常的网页进行测试,无疑会出现非常麻烦的步骤
所以我们推荐采用Postman软件,下面我们将会简单做一下介绍 Postman链接
首先为大家附上链接: 下载链接:Download Postman (getpostman.com) 文档链接:PostMan中文文档 整合链接:Apipost-API 文档、设计、调试、自动化测试一体化协作平台 Postman操作讲解
在了解操作前,我们需要明白Postman的作用: 用于分类存储网页请求 用于发送请求进行测试
关于安装注册的过程我们不再赘述 Postman页面展示
我们先来查看Postman的主页:
首先我们可以看到左上角的Workspaces,这个是最大的分类空间
我们可以看到左上角SpringMVC,这是我所创建的WorkSpaces,关于我在SpringMVC所做的网页测试部分将都在这里进行
除此之外,我们可以看到右侧的DEMO1,以及内部的测试用例文件夹,以及项目save
以上就是我们的Postman的基本页面 Postman具体使用
我们的Postman的具体使用流程如下: 创建新的Workspaces
选定主界面,创建对应文件夹
创建项目(点击中间区域的加号)
书写项目内容(GET可以更换其他类型,后面书写URL,下方key,value书写传递数据)
下方的数据传递可以更换类型,例如更换为body体的raw来书写JSON格式
书写后保存到相应列表并标注名称
到这里,我们Postman的基本使用基本就结束了,到后面我们会对具体内容做具体补充~ SpringMVC设置请求与响应
SpringMVC和Servlet同属于服务层的工具,那么必不可少的就是请求与响应的反馈问题
接下来我们将一一介绍请求与响应的相关知识 请求映射路径设置
首先我们先来想一想我们之前的路径设置是否有那么一点点缺陷? // Book的服务层 package com.itheima.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class BookController { //请求路径映射 @RequestMapping("/save") @ResponseBody public String save(){ System.out.println("book save ..."); return "{"module":"book save"}"; } } // User的服务层 package com.itheima.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController { //请求路径映射 @RequestMapping("/save") @ResponseBody public String save(){ System.out.println("user save ..."); return "{"module":"user save"}"; } //请求路径映射 @RequestMapping("/delete") @ResponseBody public String delete(){ System.out.println("user delete ..."); return "{"module":"user delete"}"; } }
我们可以注意到我们的单个项目中不可能只包括有一个服务层
但我们的请求映射路径却只是简单设计为相同的名称,就会导致我们访问该页面时,系统无法匹配
所以我们需要给他们采用不同的映射路径,我们常有的操作是直接在前面加上一层该类的路径名: package com.itheima.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class BookController { //请求路径映射 @RequestMapping("/book/save") @ResponseBody public String save(){ System.out.println("book save ..."); return "{"module":"book save"}"; } }
但当项目逐渐增多,我们多次书写路径名就有可能导致错误,所以我们采用类注解@RequestMapping来解决: package com.itheima.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @Controller //类上方配置的请求映射与方法上面配置的请求映射连接在一起,形成完整的请求映射路径 @RequestMapping("/user") public class UserController { //请求路径映射 @RequestMapping("/save") @ResponseBody public String save(){ System.out.println("user save ..."); return "{"module":"user save"}"; } //请求路径映射 @RequestMapping("/delete") @ResponseBody public String delete(){ System.out.println("user delete ..."); return "{"module":"user delete"}"; } }
注意:@RequestMapping不仅仅可以用于方法表示映射,也可以用于整个Bean类中表示映射前缀 参数传递问题
关于参数传递我们从三个方面来讲解: 传递方式 传递参数类型 特殊参数类型 按传递方式
我们的传递方式通常采用GET或者POST方式
但在前面的学习中我们可以知道我们的传递方式是有不同的,我们在Postman的书写形式也是不同的
例如我们先给出一个简单的参数传递函数 package com.itheima.controller; import com.itheima.domain.User; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Arrays; import java.util.Date; import java.util.List; //请求参数 @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 "{"module":"common param"}"; } }
我们的GET方式直接在网页后用?和&来书写传递参数:
我们的POST方式只能在下方的body中书写参数:
然后我们需要注意到的是这里的中文同样会出现乱码行为
这次我们选择在ServletContainersInitConfig中处理数据: // 下述代码基本属于我们创建项目的固定代码 package com.itheima.config; import org.springframework.web.filter.CharacterEncodingFilter; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; import javax.servlet.Filter; public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { protected Class<?>[] getRootConfigClasses() { return new Class[0]{SpringConfig.class}; } protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } //乱码处理 @Override protected Filter[] getServletFilters() { // CharacterEncodingFilter 属于处理中文编码的过滤器,我们直接创建即可(一次性操作) CharacterEncodingFilter filter = new CharacterEncodingFilter(); filter.setEncoding("UTF-8"); return new Filter[]{filter}; } } 按参数方式
我们按参数来分类主要分为五种: 普通参数 POJO类 嵌套式POJO类 数组参数 集合参数
我们下面来一一介绍 普通参数
普通参数:请求参数和形参变量名相同时,自动匹配 package com.itheima.controller; import com.itheima.domain.User; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Arrays; import java.util.Date; import java.util.List; //请求参数 @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 "{"module":"common param"}"; } }
Postman操作:
这里需要注意:当请求参数名与形参名不同时,使用@RequestParam注解关联请求参数名称与形参名称之间的关系 package com.itheima.controller; import com.itheima.domain.User; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Arrays; import java.util.Date; import java.util.List; //请求参数 @Controller public class UserController { //普通参数:请求参数名与形参名不同时,使用@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"}"; } }
Postman操作:
@RequestParam:绑定请求参数与处理器方法形参间的关系
包含有两个参数
required:是否为必传参数
defaultValue:参数默认值 POJO参数
POJO参数:请求参数名与形参对象属性名相同,定义POJO类型形参即可接收参数 package com.itheima.controller; import com.itheima.domain.User; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Arrays; import java.util.Date; import java.util.List; //请求参数 @Controller public class UserController { //POJO参数:请求参数与形参对象中的属性对应即可完成参数传递 @RequestMapping("/pojoParam") @ResponseBody public String pojoParam(User user){ System.out.println("pojo参数传递 user ==> "+user); return "{"module":"pojo param"}"; } }
Postman操作:
嵌套POJO参数
嵌套POJO参数:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数 package com.itheima.controller; import com.itheima.domain.User; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Arrays; import java.util.Date; import java.util.List; //请求参数 @Controller public class UserController { //嵌套POJO参数:嵌套属性按照层次结构设定名称即可完成参数传递 @RequestMapping("/pojoContainPojoParam") @ResponseBody public String pojoContainPojoParam(User user){ System.out.println("pojo嵌套pojo参数传递 user ==> "+user); return "{"module":"pojo contain pojo param"}"; } }
Postman操作:
数组参数
数组参数:请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型形参即可接收参数 package com.itheima.controller; import com.itheima.domain.User; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Arrays; import java.util.Date; import java.util.List; //请求参数 @Controller public class UserController { //数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中 @RequestMapping("/arrayParam") @ResponseBody public String arrayParam(String[] likes){ System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes)); return "{"module":"array param"}"; } }
Postman操作:
集合保存普通参数
集合保存普通参数:请求参数与形参集合对象名相同且请求参数为多个,@RequestParam绑定参数关系 package com.itheima.controller; import com.itheima.domain.User; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Arrays; import java.util.Date; import java.util.List; //请求参数 @Controller public class UserController { //集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据 @RequestMapping("/listParam") @ResponseBody public String listParam(@RequestParam List likes){ System.out.println("集合参数传递 likes ==> "+ likes); return "{"module":"list param"}"; } }
Postman参数:
按特殊参数方式
我们的特殊参数主要介绍两种: JSON类型 日期类型
我们下面一一介绍 JSON类型
JSON类型是我们Web开发中最常用的类型,所以这一部分算是一个小重点
我们将一一讲解JSON类型传递的步骤: 导入JSON坐标 <?xml version="1.0" encoding="UTF-8"?> 4.0.0 com.itheima springmvc_04_request_param 1.0-SNAPSHOT war javax.servlet javax.servlet-api 3.1.0 provided org.springframework spring-webmvc 5.2.10.RELEASE com.fasterxml.jackson.core jackson-databind 2.9.0 org.apache.tomcat.maven tomcat7-maven-plugin 2.1 80 / 在SpringMVC配置类中添加JSON类型转换注解 package com.itheima.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.CharacterEncodingFilter; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import javax.servlet.Filter; import javax.servlet.annotation.WebFilter; @Configuration @ComponentScan("com.itheima.controller") //开启json数据类型自动转换 @EnableWebMvc public class SpringMvcConfig { } 在Controller中书写相关Web代码(注意:需要使用@RequestBody表示将请求体数据传递给请求参数) package com.itheima.controller; import com.itheima.domain.User; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Arrays; import java.util.Date; import java.util.List; //请求参数 @Controller public class UserController { //集合参数:json格式 //1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc //2.使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据 @RequestMapping("/listParamForJson") @ResponseBody public String listParamForJson(@RequestBody List 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 list){ System.out.println("list pojo(json)参数传递 list ==> "+list); return "{"module":"list pojo for json param"}"; } }
Postman操作:
在上面我们有两个注解需要特别注意一下: @EnableWebMvc 名称:@EnableWebMvc 类型:配置类注解 位置:SpringMVC配置类定义上方 作用:开启SpringMVC多项辅助功能 @RequestBody 名称:@RequestBody 类型:形参注解 位置:SpringMVC控制器方法形参定义前面 作用:将请求中请求体所包含的数据传递给请求参数,此注解一个处理器方法只能使用一次 @RequestBody和@RequestParam区别
区别@RequestParam用于接收url地址传参,表单传参[application/x-www-form-urlencoded]@RequestBody用于接收JSON数据[application/json]应用后期开发中,发送json数据为主,@RequestBody应用较广如果发送非json格式数据,选用@RequestParam接收请求参数日期型参数类型
我们的日期类型数据基于系统不同格式也不相同,大致有以下几种: 2022-10-05 2022/10/05 10/05/2022
接收形参时,我们根据不同的日期格式设置不同的接收方式 package com.itheima.controller; import com.itheima.domain.User; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Arrays; import java.util.Date; import java.util.List; //请求参数 @Controller public class UserController { //日期参数 //使用@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"}"; } } /* 名称:@DateTimeFormat 类型:形参注解 位置:SpringMVC控制器方法前 作用:设定日期时间型数据格式 属性:pattern:日期时间格式字符串 */
Postman操作:
这里我们简单介绍一下@DateTimeFormat的转换原理Converter接口: public interface Converter{ @Nullable T convert(S var1) }
Converter接口属于顶层接口,由它为起源创建了许多相关的接口与类用于各种转化: 请求参数年龄数据(String->Integer) 日期格式转发(String->Date)
@EnableWebMvc功能之一:根据类型匹配对应的类型转换器 设置响应
在了解请求的相关知识之后,我们回到Controller代码中学习一下响应 跳转响应
在正常情况下,我们的响应给出的是当前项目的文档,相当于页面的跳转效应: package com.itheima.controller; import com.itheima.domain.User; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.ArrayList; import java.util.Date; import java.util.List; @Controller public class UserController { //响应页面/跳转页面 //返回值为String类型,设置返回值为页面名称,即可实现页面跳转 @RequestMapping("/toJumpPage") public String toJumpPage(){ System.out.println("跳转页面"); return "page.jsp"; } } 信息响应
如果我们希望得到一些信息响应,就需要采用注解解释: package com.itheima.controller; import com.itheima.domain.User; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.ArrayList; import java.util.Date; import java.util.List; @Controller public class UserController { //响应文本数据 //返回值为String类型,设置返回值为任意字符串信息,即可实现返回指定字符串信息,需要依赖@ResponseBody注解 @RequestMapping("/toText") @ResponseBody public String toText(){ System.out.println("返回纯文本数据"); return "response text"; } //响应POJO对象 //返回值为实体类对象,设置返回值为实体类类型,即可实现返回对应对象的json数据,需要依赖@ResponseBody注解和@EnableWebMvc注解 @RequestMapping("/toJsonPOJO") @ResponseBody public User toJsonPOJO(){ System.out.println("返回json对象数据"); User user = new User(); user.setName("itcast"); user.setAge(15); return user; } //响应POJO集合对象 //返回值为集合对象,设置返回值为集合类型,即可实现返回对应集合的json数组数据,需要依赖@ResponseBody注解和@EnableWebMvc注解 @RequestMapping("/toJsonList") @ResponseBody public List toJsonList(){ System.out.println("返回json集合数据"); User user1 = new User(); user1.setName("传智播客"); user1.setAge(15); User user2 = new User(); user2.setName("黑马程序员"); user2.setAge(12); List userList = new ArrayList(); userList.add(user1); userList.add(user2); return userList; } } /* 名称:@ResponseBody 类型:方法注解 位置:SpringMVC控制器方法定义上方 作用:设置当前控制器返回值作为响应体 */
当我们使用Postman访问该链接时就会给出对应反馈,这里就不做演示了 REST风格
首先我们来简单介绍一下REST: REST(Representational State Transfer),表现形式状态转换
我们给出正常风格和REST风格两种书写形式,我们可以明显看到REST的内容做出大规模的省略: 正常风格:http://localhost/user/getById?id=1 REST风格:http://localhost/users/1
REST风格优点: 书写简化 隐藏资源的访问行为,无法通过地址得知对资源的操作 REST风格简介
我们来对REST风格做出简单解释: REST风格是采用访问资源的行为动作来区别对资源进行了何种操作
我们给出五种常见行为动作: http://localhost/users:查看全部用户信息 GET(查询) http://localhost/users/1: 查看指定用户信息 GET(查询) http://localhost/users:添加用户信息 POST(新增/保存) http://localhost/users:修改用户信息 PUT(修改/更新) http://localhost/users/1: 删除用户信息 DELETE(删除)
我们通常将根据REST风格进行的访问称为RESTful 上述行为是约定方式,约定不是规范,是可以打破的,所以称为REST风格,而不是REST规范
描述模块的名称通常使用负数,也就是加s的格式描述,表示此类,而非单个资源 RESTful入门案例
从本质上而言,REST只是一种规范形式,我们对于REST的风格修改仅针对于Controller
我们下面将逐步进行RESTful的修改: 设置http请求动作 package com.itheima.controller; import com.itheima.domain.Book; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; @Controller public class BookController { // RequestMapping中包含value和method两种属性 // value:访问路径 // method:访问方法 @RequestMapping(value = "/users",method = Request.POST) @RequestBody public String save(@RequestBody User user){ System.out.println("user save" + user); return "{"module":"user save"}" } } /* 名称:@RequestMapping 类型:方法注解 位置:SpringMVC控制器方法定义上方 作用:设置当前控制器方法请求访问路径 属性:value访问路径,method请求动作 */ 设置请求参数(路径变量) package com.itheima.controller; import com.itheima.domain.Book; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; @Controller public class BookController { // 首先针对我们所需参数给出@PathVariable注解,并在访问路径中采用{}占位表示所传数据 // 简单来说就是,系统根据请求路径,得到所需数据,再带入到方法中 @RequestMapping(value = "/users/{id}" ,method = RequestMethod.DELETE) @RequestBody public String delete(@PathVariable Integer id){ System.out.println("book delete..." + id); return "{"module":"book delete"}"; } } /* 名称:@PathVariable 类型:形参注解 位置:SpringMVC控制器方法形参定义前面 作用:绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应 */
下面我们给出所有情况案例: package com.itheima.controller; import com.itheima.domain.User; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; @Controller public class UserController { //设置当前请求方法为POST,表示REST风格中的添加操作 @RequestMapping(value = "/users",method = RequestMethod.POST) @ResponseBody public String save(){ System.out.println("user save..."); return "{"module":"user save"}"; } //设置当前请求方法为DELETE,表示REST风格中的删除操作 //@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同 @RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE) @ResponseBody public String delete(@PathVariable Integer id){ System.out.println("user delete..." + id); return "{"module":"user delete"}"; } //设置当前请求方法为PUT,表示REST风格中的修改操作 @RequestMapping(value = "/users",method = RequestMethod.PUT) @ResponseBody public String update(@RequestBody User user){ System.out.println("user update..."+user); return "{"module":"user update"}"; } //设置当前请求方法为GET,表示REST风格中的查询操作 //@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同 @RequestMapping(value = "/users/{id}" ,method = RequestMethod.GET) @ResponseBody public String getById(@PathVariable Integer id){ System.out.println("user getById..."+id); return "{"module":"user getById"}"; } //设置当前请求方法为GET,表示REST风格中的查询操作 @RequestMapping(value = "/users",method = RequestMethod.GET) @ResponseBody public String getAll(){ System.out.println("user getAll..."); return "{"module":"user getAll"}"; } } /* 下述为原有代码: @RequestMapping @ResponseBody public String delete(){ System.out.println("user delete..."); return "{"module":"user delete"}"; } @RequestMapping @ResponseBody public String update(){ System.out.println("user update..."); return "{"module":"user update"}"; } @RequestMapping @ResponseBody public String getById(){ System.out.println("user getById..."); return "{"module":"user getById"}"; } @RequestMapping @ResponseBody public String getAll(){ System.out.println("user getAll..."); return "{"module":"user getAll"}"; } */ 我们在这里给出@RequestBody,@RequestParam,@PathVariable区别
区别:
@RequestParam用于接收url地址传参或表单传参@RequestBody用于接收json数据@PathVariable用于接收路径参数,使用{参数名称}描述路径参数
应用:
后期开发中,发送请求参数超过1个时,以json格式为主,@RequestBody应用较广如果发送非json格式数据,选用@RequestParam接受请求参数采用RESTful进行开发,当参数数量较少时,如1个,可以采用@PathVariable接收请求路径变量,常用来传递id值REST快速开发
我们在上一小节中会发现有许多重复性的代码: // 每次都填写value,method导致代码繁冗 // 包括每次填写ResponseBody使代码繁冗 @RequestMapping(value = "/users",method = RequestMethod.GET) @ResponseBody
所以我们可以采用一些小技巧来简化代码: 将前缀地址和相关注解放于类中: package com.itheima.controller; import com.itheima.domain.Book; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; //@Controller //@ResponseBody @RestController @RequestMapping("/books") public class BookController { } /* 正常情况下,我们的类本身具有@Controller,并且为了省略类中的@ResponseBody而直接标注在类头 但Spring提供了一种新的注解@RestController,相当于@Controller和@ResponseBody的结合,我们只需要书写这一个注解即可 名称:@RestController 类型:类注解 位置:基于SpringMVC的RESTful开发控制器类定义上方 作用:设置当前控制器为RESTful风格,等同于@Controller与@ResponseBody两个注解组合功能 */ 采用新的地址注解代替老注解: package com.itheima.controller; import com.itheima.domain.Book; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/books") public class BookController { //@RequestMapping( method = RequestMethod.POST) //使用@PostMapping简化Post请求方法对应的映射配置 @PostMapping public String save(@RequestBody Book book){ System.out.println("book save..." + book); return "{"module":"book save"}"; } //@RequestMapping(value = "/{id}" ,method = RequestMethod.DELETE) //使用@DeleteMapping简化DELETE请求方法对应的映射配置 @DeleteMapping("/{id}") public String delete(@PathVariable Integer id){ System.out.println("book delete..." + id); return "{"module":"book delete"}"; } //@RequestMapping(method = RequestMethod.PUT) //使用@PutMapping简化Put请求方法对应的映射配置 @PutMapping public String update(@RequestBody Book book){ System.out.println("book update..."+book); return "{"module":"book update"}"; } //@RequestMapping(value = "/{id}" ,method = RequestMethod.GET) //使用@GetMapping简化GET请求方法对应的映射配置 @GetMapping("/{id}") public String getById(@PathVariable Integer id){ System.out.println("book getById..."+id); return "{"module":"book getById"}"; } //@RequestMapping(method = RequestMethod.GET) //使用@GetMapping简化GET请求方法对应的映射配置 @GetMapping public String getAll(){ System.out.println("book getAll..."); return "{"module":"book getAll"}"; } } /* 名称:@GetMapping @PostMapping @PutMapping @DeleteMapping 类型:方法注解 位置:基于SpringMVC的RESTful开发控制器方法定义上方 作用:设置当前控制器方法请求访问路径与请求动作,每种对应一个请求动作,例如@GetMapping对应GET请求 参数:value请求访问路径 */ 结束语
好的,关于SpringMVC的内容就介绍到这里,希望能为你带来帮助!
有哪些令人难以置信的真实故事?2001年9月,台湾富豪洪若潭携同年轻的妻子,钻进自己定制的焚化炉里,关门启动燃烧,只用了几分钟,两个人就结束了生命,他还留有遗书我那三个孩子已经被烧死,并且骨灰已经扔到大海里。这
双减培训机构瞄准老年人,全民读书学习时代会替代全民打麻将吗?还真是一个好的想法如果这些培训机构有章可循有法可依,真正为老年朋友开办一些正规的有质量的兴趣班,那老年大学就不至于挤破头了。随着国家针对义务教育双减政策的出台和校外培训机构的取缔,
民国时期湖南广东江西三省交界的大土匪周文山,当年到底有多坏?民国诸匪之中,周文山可谓是猥琐发展流的代表。此人从表面上来看真是没有一丝可取之处,长相丑陋猥琐谨慎文不成武不就贪财好色不讲道义等等,就这么一个人却成了纵横湘粤赣三省的巨匪,这完全是
裸辞代价有多大?上周五,丽丽果断地裸辞了。过往的职场生活里,长期加班天天开会挨批忙到一点私人空间都没有,让丽丽觉得身心疲惫,一想到上班我就头疼。于是她想到了裸辞。辞去工作之后,再不用拼命挤上满人的
昆明6070后能一次交社保吗?昆明6070后能一次交社保吗?现在一次性补缴的政策基本上都是收紧了的,对于灵活就业人员城镇个体工商户等不能通过向前补缴的方式增加缴费年限,允许补缴的情况基本上是属于在用人单位应保未
被法院列入失信黑名单后,生活会受到什么样的影响?本人在失信人名单上,我来说说我的生活受到了什么影响。首先阐明一点,我不是老赖。因为从2014年破产到现在,我没有转移过一分钱。甚至在我破产的前一天我还做着起死回生的春秋大梦。对自己
有些惨案中好几个人打不过一个持刀的凶手,人手上有刀真的可怕吗?以前学散打的时候,有个当刑警的朋友说过一个案例,我至今都记忆犹新!刑警朋友说,在抓捕罪犯的过程中,最危险的就是碰到有手枪的,其次就是拿匕首的歹徒!由此可见,持有匕首短刀的人是非常危
夏明回归,赵显坤胜利,苏筱凭什么打败了资本?这个局设计的有点扯蛋,夏明的那块农业用地究竟多少面积折合多少资产没有交待,这块地的取得方式也没有交待,是租借的农村集体用地还是取得合法产权的用地,根据土地法,农村的集体用地是不可以
农村社保有什么用?今天和大家分享的是农村社保卡有什么用处?这些用处村民们务必了解!最近几年,国家对农村的惠民政策越来越多了,尤其是对农民的身体健康方面,国家推行了社保,很多农民都参加了社保,但是农村
甘肃警察职业学院入警率怎么样?甘肃警察职业学院是公安部教育部核准的专科层次的全日制公安高等职业学院,隶属甘肃省公安厅领导和管理。学院现有大砂坪和皋兰2个校区,总占地面积超过2000亩,校舍建筑面积超过20万平方
80后的你现在有多少资产?我生于1982年,现在和老公名下有房产两套,门面一个,车子一辆,两个孩子。看起来日子光鲜亮丽,内地里其实捉襟见肘。我虽然生活在四线小城市,但也是全国幸福指数排名靠前的小城市,依山傍