SpringMVC
文章目录
- SpringMVC
- 学习目标
- SpringMVC简介
- 优点
- 入门案例
- springmvc入门程序开发流程
- 入门案例工作流程分析
- SpringMVC对应bean加载与spring对应bean加载
- web配置类简化开发
- PostMan插件
- 简介
- 基本使用
- 请求与响应
- 请求映射路径
- 请求参数
- 请求方式
- 请求参数(传递json数据)
- 日期类型参数传递
- 响应
- REST风格
- RESTful入门案例
- REST快速开发
- 案例:基于RESTful页面数据交互
学习目标
- 掌握基于SpringMVC获取请求参数与响应json数据操作
- 熟练应用基于REST风格的请求路径设置与参数传递
- 能够根据实际业务建立前后端开发通信协议并进行实现
- 基于SSM整合技术开发任意业务模块功能
SpringMVC简介
- SpringMVC技术与Servlet技术功能等同,均属于web层开发技术
- SpringMVC是一种基于Java实现MVC模型的轻量级web(表现层)框架
- SpringMVC是一种表现层框架技术,用于进行表现层功能开发
优点
- 使用简单,开发便捷(相比于Servlet)
- 灵活性强
入门案例
-
使用SpringMVC技术需要先导入SpringMVC坐标与Servlet坐标
<dependencies> <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> </dependencies>
-
创建SpringMVC控制器类(等同于Servlet功能)
//定义表现层控制器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环境),设定SpringMVC加载对应的bean
//springmvc配置类,本质上还是一个spring配置类 @Configuration @ComponentScan("com.itheima.controller") public class SpringMvcConfig { }
-
加载SpringMVC环境,并设置SpringMVC技术处理的请求,专用于加载springmvc的核心配置,我们需要做的就是创建空容器并注册,返回出去
//4.定义一个servlet容器的启动配置类,在里面加载springmvc的配置 public class ServletContainitConfig extends AbstractDispatcherServletInitializer { //加载Springmvc容器配置的 @Override protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); //上方操作完成后并未加载MVC的配置,所以是一个空的容器,需要以下操作来加载配置 ctx.register(SpringMvcConfig.class); return ctx; } //设置哪些请求归springmvc处理的 @Override protected String[] getServletMappings() { return new String[]{"/"}; } //加载spring容器配置,注意与springMVC区分 @Override AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); //上方操作完成后并未加载MVC的配置,所以是一个空的容器,需要以下操作来加载配置 ctx.register(SpringConfig.class); return ctx; }
5.导入tomcat坐标
<build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.1</version> <configuration> <port>80</port> <path>/</path> </configuration> </plugin> </plugins> </build>
springmvc入门程序开发流程
- 一次性工作
- 创建工程,设置服务器,加载工程
- 导入坐标
- 创建web容器启动类,加载springMVC配置,并设置SpringMVC请求拦截路径
- springmvc核心配置类,(设置配置类,扫描controller包,加载Controller控制器bean)
- 多次工作
- 定义处理请求的控制器类
- 定义处理请求的控制器方法,并设置映射路径@RequestMapping(“”),与返回json数据@ResponseBody
入门案例工作流程分析
-
启动服务器初始化过程
- 服务器启动,执行ServletContaInitConfig类,初始化web容器
- 执行createServletApplicationContext()方法,创建WebApplicationContext对象
- 加载SpringMvcConfig
- 执行@Controller加载对应的bean
- 加载UserController,每个@RequestMapping(“”)对应一个具体的方法
- 执行 getServletMappings()方法,定义所有的请求都通过SpringMVC
-
单次请求过程
- 发送localhost/save
- web容器发现所有请求都经过SpringMVC,将请求交给springMVC
- 解析请求路径/save
- 由/save匹配执行对应的方法save()
- 执行save()
- 检测到有@ResponseBody直接将save()方法的返回值作为响应体交给请求方
SpringMVC对应bean加载与spring对应bean加载
- SpringMVC相关bean(表现层bean)
- Spring控制的bean
- 业务bean(Service)
- 功能bean(DataSource等)
产生问题:因为功能不同如何避免Spring错误加载到SpringMVC的bean?
-
方案
- 加载Spring控制的bean的时候,排除掉SpringMVC控制的bean
-
SpringMVC相关的bean控制
- springMVC加载的包对应的包均在com.ityc.controller包内
-
Spring相关bean加载控制
- 方式一:Spring加载的bean设定扫描范围为com.ityc,排除掉controller包内的bean
- 方式二:Spring加载的bean设定骚尼奥范围为精准范围,例如:service包,dao包等
- 方式三:不区分spring与soringMVC的环境,加载在同一环境中
//创建Spring的配置文件,
@Configuration
//方案1
//@ComponentScan({"com.ityc.service","com.ityc.dao"})
//方案二
//设置spring配置类加载bean时的过滤规则,当前要求排除掉表现层对应的bean
//excludeFilters属性:设置扫描加载bean时,排除的过滤规则
//type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除
//classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean
@ComponentScan(value = "com.ityc",
excludeFilters =@ComponentScan.Filter(
type = FilterType.ANNOTATION,//使用此方式,将排除我们指定的注解对应的包,spring就不会加载本包对应的bean
classes = Controller.class
)
)
public class SpringConfig {
}
web配置类简化开发
配置环境
extends AbstractAnnotationConfigDispatcherServletInitializer
//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[]{"/"};
}
}
/*
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
*/
PostMan插件
简介
- PostMan是一款功能强大的网页调试与发送网页http请求的Chrome插件
- 作用:常用于接口测试
- 特征:
- 简单
- 实用
- 美观
- 大方
基本使用
- 注册登录
- 创建工作空间/进入工作空间
- 发起请求测试结果
请求与响应
请求映射路径
思考:
1.团队多人开发,没人设置不同的请求路径,冲突问题如何解决?~设置模块名作为请求路径前缀
@Controller
//请求路径的前缀
//代表该模块所有的请求路径前都加book
@RequestMapping("/book")
public class BookController {
@RequestMapping("save")
@ResponseBody
public String save(){
System.out.println("book save...");
return "{'module':'book save'}";
}
@RequestMapping("delete")
@ResponseBody
public String delete(){
System.out.println("book delete...");
return "{'module':'book delete'}";
}
}
请求参数
(传参)
请求方式
-
Get请求
- http://localhost/commonParam?name=yc&age=18
-
Post请求
-
postMan发送携带参数Post请求
-
springMvc解决Post请求中文乱码问题
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}; // return new Filter[]{filter,filter2,filter3}; } }
-
-
参数种类
- 普通参数
- POJO类型参数
- 嵌套POJO类型参数
- 数组类型参数
- 集合类型参数
-
不同类型的参数的传递
@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){ //@RequestParam("name")利用该注解,绑定name到username,也就是绑定请求参数与形参之间的关系 System.out.println("普通参数传递 name ==> "+username); System.out.println("普通参数传递 age ==> "+age); return "{'module':'commonDifferentName param'}"; } //pojo参数,实体类 @RequestMapping("/pojoParam") @ResponseBody public String pojoParam(User user){ System.out.println("pojo参数传递 user ==> "+user); return "{'module':'pojo param'}"; } //pojo嵌套参数 @RequestMapping("/pojoContainParam") @ResponseBody public String pojoContainParam(User user){ System.out.println("pojo参数传递 user ==> "+user); return "{'module':'pojo param'}"; } //数组参数 @RequestMapping("arrayParam") @ResponseBody public String arrayParam(String[] likes){ System.out.println("数组参数传递 user ==> "+Arrays.toString(likes)); return "{'module':'array param'}"; } //集合参数 @RequestMapping("listParam") @ResponseBody public String listParam(@RequestParam List<String> likes){ System.out.println("集合参数传递 user ==> "+likes); return "{'module':'list param'}"; } }
-
请求参数与形参名不同解决完成参数传递利用@RequestParam注解
请求参数(传递json数据)
步骤:
//1.pom.xml导入json坐标
//2.在springmvc配置中中开启开启json数据类型自动转换
@EnableWebMvc
//3.@RequestBody 注解
- json数组
- json对象(pojo)
- json数组(pojo)
//数组参数:(JSON)格式
@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List<String> likes){
System.out.println("集合参数传递 user ==> "+likes);
return "{'module':'list param'}";
}
//集合参数:(JSON)格式
@RequestMapping("/pojolistParamForJson")
@ResponseBody
public String pojoParamForJson(@RequestBody User user){
System.out.println("集合参数传递 user ==> "+user);
return "{'module':'pojolist param'}";
}
//pojo参数:(JSON)格式
@RequestMapping("/listPojoParamForJson")
@ResponseBody
public String listPojoParamForJson(@RequestBody List<User> list){
System.out.println("集合参数传递 user ==> "+ list);
return "{'module':'Pojo param'}";
}
@RequestBody与@RequestParam区别
- 区别:
- @RequestParam用于接收url地址传参,表单传参(application/x-www-form-urlencoded)
- @RequestBody用于接收json数据(application/json)
- 应用
- 后期开发中发送json格式数据为主@RequestBody应用广泛
- 如果发送非json数据,选用@RequestParam接收请求参数
小结:
1.json数据传递与接收
2.@EnableWebMvc注解
3.@RequestBody
日期类型参数传递
- 日期类型数据基于系统不同格式也不尽相同
- 2011-01-11
- 2011/01/11
- 01/11/2011
//日期型参数
@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("参数传递yyyy-MM-dd date1 ==> "+ date1);
System.out.println("参数传递yyyy/MM/dd HH:MM:SS date2==> "+ date2);
return "{'module':'date param'}";
}
响应
- 响应页面
- 响应数据
- 文本数据
- json数据
@Controller
public class UserController {
//响应页面/跳转页面
//返回值为String类型,设置返回值为页面名称,即可实现页面跳转
@RequestMapping("/toJumpPage")
public String toJumpPage(){
System.out.println("跳转页面");
return "page.jsp";
}
//响应文本数据
//返回值为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<User> toJsonList(){
System.out.println("返回json集合数据");
User user1 = new User();
user1.setName("ityc");
user1.setAge(15);
User user2 = new User();
user2.setName("itheima");
user2.setAge(12);
List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);
return userList;
}
}
注解:@ResponseBody
- 位置:SpringMvc控制器方法定义上方
- 作用:
- 设置当前控制器,方法响应内容为当前返回值,无需解析
- 设置当前控制器返回值为响应体
类型转换器
- HttpMessageConverter接口
REST风格
-
REST简介
- 表现形式状态转换
-
传统风格资源描述形式
http://localhost/user/getId?id=1 http://localhost/user/saveUser
-
REST风格描述形式
http://localhost/user/1 http://localhost/user
-
优点:
- 隐藏资源的访问行为,无法通过地址得知对资源是何种操作
- 书写简化
-
按照REST风格访问资源时使用行为动作区分对资源进行了何种操作
http://localhost/users 查询全部用户信息 GET(查询) http://localhost/users/1 查询指定用户信息 GET(查询) http://localhost/users 添加用户信息 POST(新增/保存) http://localhost/users 修改用户信息 PUT(修改/更新) http://localhost/users/1 删除用户信息 DELETE(删除)
注意:
上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范,
描述模块的名称通常使用复数,也就是加S的格式描述,而非单个资源,例如:users,books,accounts…
-
根据REST风格对资源进行访问称为RESTful
RESTful入门案例
步骤:
1.设定http请求动作:post,get,put等等
2.设置请求参数(路径变量)
- 路径中要有我们的参数占位
- 在方法形参中与占位变量对应上,并且加上@PathVariable注解
//请求方法设定
@Controller
//请求路径的前缀
public class BookController {
@RequestMapping(value = "/users",method = RequestMethod.POST)
@ResponseBody
public String save(){
System.out.println("book save...");
return "{'module':'user save'}";
}
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
System.out.println("book delete..."+id);
return "{'module':'book delete'}";
}
@RequestMapping(value = "/users",method = RequestMethod.PUT)
@ResponseBody
public String update(@RequestBody User user){
System.out.println("book PUT..."+user);
return "{'module':'book PUT'}";
}
@RequestMapping(value = "/users/{id}",method = RequestMethod.GET)
@ResponseBody
public String getById(@PathVariable Integer id){
System.out.println("book id..."+id);
return "{'module':'book id'}";
}
@RequestMapping(value = "/users",method = RequestMethod.GET)
@ResponseBody
public String getAll(){
System.out.println("book getALL...");
return "{'module':'book GETALL'}";
}
}
- 区分@RequestBody @RequestParam @PathVariable
- 区别:
- @RequestParam:用于接收url地址传参或表单传参
- @RequestBody:用于接收json数据
- @PathVariable:用于接收路径参数,使用{参数名称}描述路径参数
- 应用:
- 后期开发中,发送请求参数超过一个时,以json格式为主,@RequestBody应用较广
- 如果发送非json格式数据,则采用@RequestParam接收请求参数
- 采用RESTful进行开发,当参数数量较少是,例如一个,则可以采用@PathVariable接收请求路径变量,通常用于传递id值。
REST快速开发
-
@RestController注解
- 设置当前控制器类为RESTful风格,等同于@Controller与@ResponseBody两个注解的组合
-
@PostMapping,@PutMapping,@GetMapping,@DeleteMapping
- 设置当前控制器方法请求访问路径与请求动作,每种对应一种请求动作,例如@PostMapping对应post请求
//@Controller //请求路径的前缀 //@ResponseBody @RestController @RequestMapping("users") public class BookController { //@RequestMapping(method = RequestMethod.POST) @PostMapping public String save(){ System.out.println("book save..."); return "{'module':'user save'}"; } //@RequestMapping(value = "/{id}",method = RequestMethod.DELETE) @DeleteMapping("{id}") public String delete(@PathVariable Integer id){ System.out.println("book delete..."+id); return "{'module':'book delete'}"; } //@RequestMapping(method = RequestMethod.PUT) @PutMapping public String update(@RequestBody User user){ System.out.println("book PUT..."+user); return "{'module':'book PUT'}"; } //@RequestMapping(value = "/{id}",method = RequestMethod.GET) @GetMapping("{id}") public String getById(@PathVariable Integer id){ System.out.println("book id..."+id); return "{'module':'book id'}"; } //@RequestMapping(method = RequestMethod.GET) @GetMapping public String getAll(){ System.out.println("book getALL..."); return "{'module':'book GETALL'}"; } }
案例:基于RESTful页面数据交互
-
制作SpringMVC控制器,并通过PostMan测试接口功能。
-
设置对静态资源的访问放行
-
前端页面通过异步提交访问后台控制器
//注意:要在SpringMVC中添加本配置 @Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { //当访问/pages/????时不要走mvc,走/pages目录下的内容 registry.addResourceHandler("/pages/**").addResourceLocations("/pages/"); registry.addResourceHandler("/js/**").addResourceLocations("/js/"); registry.addResourceHandler("/css/**").addResourceLocations("/css/"); registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/"); } }
//添加 saveBook () { axios.post("http://localhost/books.",this.formData).then((res)=>{ }); }, //主页列表查询 getAll() { axios.get("http://localhost/books.").then((res)=>{ this.dataList = res.data; }); },
//案例
@RestController
@RequestMapping("/books")
public class BookController {
@PostMapping
public String save(@RequestBody Book book){
System.out.println("book save ====>"+book);
return "{'module':'book save success'}";
}
@GetMapping
public List<Book> getAll(){
System.out.println("book getAll is running...");
ArrayList<Book> bookList = new ArrayList<Book>();
Book book1 = new Book();
book1.setType("计算机");
book1.setName("SpringMVC入门教程");
book1.setDescription("试试就是是");
bookList.add(book1);
Book book2 = new Book();
book2.setType("计算机2");
book2.setName("Spring入门教程");
book2.setDescription("试是实施");
bookList.add(book2);
Book book3 = new Book();
book3.setType("计算机3");
book3.setName("Spring进阶");
book3.setDescription("实事求是");
bookList.add(book3);
return bookList;
}
}
小结:
- 先做好后台功能,开发接口并调通接口
- 再做页面异步调用,确认功能可以正常访问
- 最后完成页面数据展示
- 补充:放行静态资源访问