目录
一,SpringMvc简介
1.SpringMvc概述
1.1,请求响应的演进过程
1.2,Springmvc概述
2.入门案例
2.1,servlet和springmvc开发web程序的流程
2.2,springmvc开发web程序
3.入门案例流程分析
3.1,启动服务器初始化的过程
3.2单次请求的过程
4.Controller加载控制器
4.1精准读取
4.2过滤
4.3, 加载springmvc和spring容器
二,请求与相应
1.请求映射路径
1.1定义请求路径前缀
2.请求参数
Usercontroller类:
2.1get请求和post请求
2.3指定编码格式
3,五种类型参数传递
3.1,pojo
3.2,嵌套pojo类型
3.3,数组类型
4.响应json数据
4.1,前置工作
4.2,json数组
4.3,json对象
4.4,json数组(pojo)
编辑 5.传递日期参数
补充:@ResponseBody注解
三,Rest风格
1.rest风格简介
2.restful入门案例
3.rest快速开发
最后
1.1.1,三层架构
web层:收集页面数据,产生页面
service层:业务处理
dao层:负责数据的持久化
缺点:一个servlet只可以处理一个请求
1.1.2,mvc模式
工作流程:首先浏览器发起请求给我们的controller然后,controller调用我们的service业务层,service层再调用我们的dao层,dao层返回数据给我们的service层,service层再返回数据形成一个Model,但是Model是一个Java的模型,浏览器是识别不了的,所以这个时候View+Model一起同时工作,形成页面返回给我们的浏览器。
解决的问题:这就解决了上述的三层架构的弊端,可以使用一个servlet处理多个请求。、
1.1.3,异步调用
工作流程:通过异步调用的形式,调用我们的后端服务器,后端服务器会产生一个Model对象,后端服务器再将Model对象转化为josn的格式返回给我们的前端页面。
springMvc在其中是负责controller对应的功能开发,并且将我们的数据转化为json格式
这些东西我们在后面都会明白的。
2.2.1首先创建好一个web工程,在pom文件中导入tomcat7插件(在这里就不演示如何创建一个web工程了,因为不同的idea版本有不同的创建方式)
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
/
2.2.2 写好配置类,处理器类和web配置类
配置类:
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 {
}
处理类:
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配置类:
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容器配置类
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() {
//代表所有的请求都是归springmvc处理
return new String[]{"/"};
}
//加载spring配置类
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
2.2.3,创建tomcat服务器
如下图,1.我们点击添加配置,2.然后选择maven,3.编辑maven工程的名称,4.选在工作目录,5.输入命令tomcat7:run 运行。
在这里启动刚刚配置的maven工程
2.2.3,插曲
我们可以看到,这里出现了报错,可以看到是因为端口被占用,所以我们可以换一个端口
我们在pom文件中修改tomcat运行端口为8081,再次运行后发现可以运行成功。所以问题解决。
可以看到,我们成功的连上了。
2.2.5,一些小细节
1.由于save()方法体上加上了@ResponseBody,所以返回的数据就会被当作json数据而被直接返回给页面,如果不加的话我们所要返回的{'info':'springmvc'}是无法被浏览器识别的,而且浏览器还会报404,因为他以为你要返回的还是页面。
2.要注意这个配置类所继承的类,而且这个配置类需要重写以下三个方法,来正常响应我们的请求和响应。
//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() {
//代表所有的请求都是归springmvc处理
return new String[]{"/"};
}
//加载spring配置类
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
web容器 -> webApplication 对象-> servletContext(web容器中最大的范围)-> 加载bean到webApplication 对象中。
所有的映射是放在一起统一管理的,而不是放在bean里面
其实我们现在产生了一个问题,就是说,当我们加载bean的时候,springmvc会读取bean,spring也会读取bean,但是我们要怎样才可以防止spring读取我们的controller呢?有两种方法
我们在spring配置类上,配置只去扫描两个包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 {
}
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
//设置spring配置类加载bean时的过滤规则,当前要求排除掉表现层对应的bean
//excludeFilters属性:设置扫描加载bean时,排除的过滤规则
//type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除
//classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean
@ComponentScan(value="com.itheima",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
)
public class SpringConfig {
}
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[]{"/"};
}
}
简化版和上面的意思是一样的,但是我们在现实的开发中用的最多的还是简化版:
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[]{"/"};
}
}
我们在类上面加上@RequestMapping("/user"),这时访问的完整路径就是localhost:端口号/usr/*
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'}";
}
}
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'}";
}
//普通参数:请求参数名与形参名不同时,使用@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'}";
}
}
普通参数:请求参数名与形参名不同时,使用@RequestParam注解关联请求参数名称与形参名称之间的关系
我们在PostMan上输入地址http://localhost:8082/commonParam?name=zhansan&age=15,并且是get请求。
可以看url上面的参数已经被拿到了。我们会发现url上面的参数会自动传递到我们的形参上。
再使用post请求发送,我们发现,还是可以返回数据。
我们可以知道,controller和servlet不一样,没有doGet和doPost方法,因为本身不会区分post和get。
当我们的url中含有中文的时候,我们就需要使用过滤器来指定编码格式,方式乱码,而这个过滤器我们是在web配置类中指定。
web配置类代码如下:
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];
}
protected Class>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
//乱码处理
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
}
controller:
//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(User user){
System.out.println("pojo参数传递 user ==> "+user);
return "{'module':'pojo param'}";
}
这里参数就正常传递就好,比如说url= http://localhost:8082/commonParam?name=zhansan&age=15
对应的写法:
@RequestMapping("/pojoContainPojoParam")
@ResponseBody
public String pojoContainPojoParam(User user){
System.out.println("pojo嵌套pojo参数传递 user ==> "+user);
return "{'module':'pojo contain pojo param'}";
}
但是这里在参数传递的时候有点不同。可以看到我们在给嵌套类型传参的时候,需要使用对象.属性的方式。
//数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
@RequestMapping("/arrayParam")
@ResponseBody
public String arrayParam(String[] likes){
System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes));
return "{'module':'array param'}";
}
传参时,会把你传递的所有参数放入数组里面。注意,写的时候,你的key需要放入的是你的数组名,而不可以放其他的名字。
3.4,集合参数
//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List likes){
System.out.println("集合参数传递 likes ==> "+ likes);
return "{'module':'list param'}";
}
传参的方式和数组的方式是一样的。
导入json依赖
com.fasterxml.jackson.core
jackson-databind
2.9.0
发送json数据
在mvc配置类中添加注解@EnableWebMvc,使其可以将接到的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
//集合参数: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'}";
}
传参:
controller:
//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'}";
}
传参:注意传参的格式
假设里面嵌套了一个pojo,那么传参如下。
controller:
//集合参数: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'}";
}
传参格式:
controller
//日期参数
//使用@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'}";
}
默认标准的日期格式是 2001/3/21,而使用其他的日期格式如果不加处理的话,那么就会报错,这里也提供了一个注解去创建你可能会接到的的日期格式。
这里需要提到一个重要的接口convert接口,他有许多的实现类,来帮我们进行数据格式转换。
其中转换的过程是一个新的接口HttpMessageConvert接口帮我们实现的,而不是convert接口。
这个接口可以将我们的对象数据转换成json数据返回。
原理:是通过访问的方法来区别资源(路径+请求方式)
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'}";
}
*/
值得注意的是,当我们需要通过rest风格访问并且传递参数时,我们需要在形参面前加上 @PathVariable Integer注解,并且设置访问路径的参数和形参相对应,如:/users/{id},对应形参id。如:
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
System.out.println("user delete..." + id);
return "{'module':'user delete'}";
}
是对rest开发的简化
package com.itheima.controller;
import com.itheima.domain.Book;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
//@Controller
//@ResponseBody配置在类上可以简化配置,表示设置当前每个方法的返回值都作为响应体
//@ResponseBody
@RestController //使用@RestController注解替换@Controller与@ResponseBody注解,简化书写
@RequestMapping("/books")
public class BookController {
// @RequestMapping( method = RequestMethod.POST)
@PostMapping //使用@PostMapping简化Post请求方法对应的映射配置
public String save(@RequestBody Book book){
System.out.println("book save..." + book);
return "{'module':'book save'}";
}
// @RequestMapping(value = "/{id}" ,method = RequestMethod.DELETE)
@DeleteMapping("/{id}") //使用@DeleteMapping简化DELETE请求方法对应的映射配置
public String delete(@PathVariable Integer id){
System.out.println("book delete..." + id);
return "{'module':'book delete'}";
}
// @RequestMapping(method = RequestMethod.PUT)
@PutMapping //使用@PutMapping简化Put请求方法对应的映射配置
public String update(@RequestBody Book book){
System.out.println("book update..."+book);
return "{'module':'book update'}";
}
// @RequestMapping(value = "/{id}" ,method = RequestMethod.GET)
@GetMapping("/{id}") //使用@GetMapping简化GET请求方法对应的映射配置
public String getById(@PathVariable Integer id){
System.out.println("book getById..."+id);
return "{'module':'book getById'}";
}
// @RequestMapping(method = RequestMethod.GET)
@GetMapping //使用@GetMapping简化GET请求方法对应的映射配置
public String getAll(){
System.out.println("book getAll...");
return "{'module':'book getAll'}";
}
}
注意点:
1.@RestController等于@ResponseBody+@Controller
2.@DeleteMapping("/{id}")等于@RequestMapping(value = "/{id}" ,method = RequestMethod.DELETE)
本篇博客对sprinmvc的介绍就到这里了,如果本篇博客对你有帮助的话,请点一个小赞支持一下,感谢!我们下篇博客再见!