扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
在之前的文章中我们已经学习了Spring的基本内容,SpringMVC隶属于Spring的一部分内容
我们提供的服务有:成都做网站、网站建设、微信公众号开发、网站优化、网站认证、彭水苗族土家族ssl等。为1000多家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的彭水苗族土家族网站制作公司
但由于SpringMVC完全针对于服务层使用,所以我们在介绍时常常把SpringMVC单独当作一个大章节来学习
温馨提醒:在学习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版:
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
/
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'}";
}
}
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和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类
最后我们总结一下上述操作的出现频率:
在分析SpringMVC工作流程前,我们需要知道服务层是由下面的框架组成的:
启动服务器初始化过程:
单次请求过程:
在学习SpringMVC之后,我们的Bean的范围逐渐变大:
但是我们在使用时,需要区分相关bean的导入路径:
因而我们给出两种方法来解决Spring的扫描问题:
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)
*/
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容器中可以定义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的继承类
我们同样继承它的三个方法,但这次我们只需要在里面标明相关类和路径即可
在我们的SpringMVC中岔开一个话题:
我们在一个网页开发中,会不断的调试网页,通过各种路径反复查询或者采用不同的访问方式(GET/POST)
如果我们采用正常的网页进行测试,无疑会出现非常麻烦的步骤
所以我们推荐采用Postman软件,下面我们将会简单做一下介绍
首先为大家附上链接:
在了解操作前,我们需要明白Postman的作用:
关于安装注册的过程我们不再赘述
我们先来查看Postman的主页:
首先我们可以看到左上角的Workspaces,这个是最大的分类空间
我们可以看到左上角SpringMVC,这是我所创建的WorkSpaces,关于我在SpringMVC所做的网页测试部分将都在这里进行
除此之外,我们可以看到右侧的DEMO1,以及内部的测试用例文件夹,以及项目save
以上就是我们的Postman的基本页面
我们的Postman的具体使用流程如下:
到这里,我们Postman的基本使用基本就结束了,到后面我们会对具体内容做具体补充~
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};
}
}
我们按参数来分类主要分为五种:
我们下面来一一介绍
普通参数:请求参数和形参变量名相同时,自动匹配
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类型形参即可接收参数
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属性参数
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类型是我们Web开发中最常用的类型,所以这一部分算是一个小重点
我们将一一讲解JSON类型传递的步骤:
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
/
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 {
}
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操作:
在上面我们有两个注解需要特别注意一下:
@RequestBody和@RequestParam区别
- 区别
- @RequestParam用于接收url地址传参,表单传参[application/x-www-form-urlencoded]
- @RequestBody用于接收JSON数据[application/json]
- 应用
- 后期开发中,发送json数据为主,@RequestBody应用较广
- 如果发送非json格式数据,选用@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 {
//日期参数
//使用@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接口属于顶层接口,由它为起源创建了许多相关的接口与类用于各种转化:
@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的内容做出大规模的省略:
REST风格优点:
我们来对REST风格做出简单解释:
我们给出五种常见行为动作:
我们通常将根据REST风格进行的访问称为RESTful
上述行为是约定方式,约定不是规范,是可以打破的,所以称为REST风格,而不是REST规范
描述模块的名称通常使用负数,也就是加s的格式描述,表示此类,而非单个资源
从本质上而言,REST只是一种规范形式,我们对于REST的风格修改仅针对于Controller
我们下面将逐步进行RESTful的修改:
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值
我们在上一小节中会发现有许多重复性的代码:
// 每次都填写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的内容就介绍到这里,希望能为你带来帮助!
该文章属于学习内容,具体参考B站黑马程序员李老师的SSM框架课程
这里附上链接:SpringMVC-01-SpringMVC简介_哔哩哔哩_bilibili
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流