Springmvc表述层(Controleer层)框架
一:SpringMvc简介和快速入门
1.1:介绍:
1.SpringMvc是一个Web框架,作用于表述层(Controller层); (也叫SpringWebMvc,是基于Spring Framework)
它内部封装的是:Servlet;是基于Servlet的框架
2. 之前我们进行操作是:: 1.接收前端参数
2.调用业务逻辑(Service层)
3.响应前端数据
SpringMvc重要作用!!!!:
简化接收前端参数;
简化响应给前端数据
3.我们需要学习/重点掌握:如何SpringMvc如何 简化接收前端参数:普通参数、JSON参数、文件、cookic、session!!!!!
如何简化返回给前端的数据:!!!!!!!!!
1.2:SpringMvc内部流程和核心组件
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
执行过程:
SpringMvc是基于Servlet的框架:内部封装了dServlet
之后前端所有的请求全都会交给 dServlet去处理,然后,Servlet通过请求路径去到HandlerMapping中去找有没有对应handler方法;
然后:
(1)核心组件:
SpringMvc提供了类(组件),我们只需要进行ioc配置,使其加入ioc容器即可!!!;
1.DispatcherServlet[CEO]:SpringMvc提供,他是整个流程处理的核心,所有的(请求)都要经过它的处理和分发!!
2.HandlerMapper[秘书]:它内部缓存了handler(controller的方法) 和 handler的访问路径数据,
!!被DispatcherServlet调用,用于:!!!!查找路径对应的handler;
3.HandlerAdapter[经理]:!!处理请求参数和处理响应数据,
每次DS都是通过它间接调用handler,他是DS和handler之间的适配器;
4.Handler:处理器,是Controller层的方法的简称;(我们把Controller层的每个方法称为1个Handler)
它需要我们自己定义,!!用来接收参数,向后调用业务层(Service层),最终完成响应结果!!!;
5.ViewResolver:视图解析器
(2)操作方法/流程: ~!!!!!!!!!!!! !!!!!!!!!!
我们只需要将DispatcherServlet配置到生效
将.HandlerMapper 和 HandlerAdapter放到ioc容器
最后我们自己再定义handler即可
(4.)SpringMVc内部调用流程:
1.3 SpringMvc快速入门:
springmvc-base-quick-01!!!
需求:
定义1个hanlder,只要外部访问hanler方法对应的地址,我们响应给前端 ”hello springmvc“;
分析:
1. DispatcherServlet,设置处理所有请求!,使它生效!
2. HandlerMapping,HandlerAdapter,Handler需要加入到IoC容器,供DS调用!
3. Handler自己声明(Controller)需要配置到HandlerMapping中供DS查找!
过程:!!!!!!!!!
1.创建Controller类:并添加到ioc容器
2.在Controller类中定义handler方法,
使用@RequestMapping 将handler添加到HandlerMapping + 指定外部访问路径
3.创建配置类:将 HandlerMapper、controller、HandlerAdapter 加入ioc容器
4.创建初始化类:完成web加载、ioc容器创建、Servlet拦截;路径
二:SpringMvc接收数据
springmvc-base-input-02
重点学习:
SpringMvc如何在handler方法中简化参数的接收
访问过程:
handler最终是被客户端(浏览器)访问的;
-->客户端通过http协议(get、post、put、delete)先访问到dServlet-->最后再访问到handler;
2.1:如何设置访问路径:路径设置注解@RequestMapping:
访问路径:客户端通过访问路径访问到资源(eg:dServlet);
@Controller //将Controller类加到ioc容器;
@RequestMapping("/user")
//@RequestMapping:加到类上:将方法公共的地址:/user,加到类上,下面的方法只写方法特有的地址!!!!
public class UserController {
/*
@RequestMapping:
1.作用:注册地址:
将handler方法注册到RequestMapping中,且在内部可以设置访问路径
2.@RequestMapping中的访问地址:不一定以 "/"开头。 eg:/user/login、 user/login
原来web.xml文件中必须以'/'开头
3. (1)设置精准地址:({"地址1","地址2"...})
(2)设置模糊地址:"*":任意一层字符串; "**":任意层任意字符串;
eg: 如果我们在@RequestMapping:内写的是:/user/*:
那我们在外部:使用:/user/a 、/user/aaa 都可以访问到;
4.@RequestMapping路径设置注解: 可以加到方法上,也可以加到类上;
区别:
加到方法上的:具体的handler地址
加到类上的:是提取的类下方法的通用/公共的部分地址; eg:/user
方法上是必须加,类上可以不加;
5.请求方式指定:
访问过程:
handler最终是被客户端(浏览器)访问的;
-->客户端通过http协议(get、post、put、delete)先访问到dServlet-->最后再访问到handler;
如何指定请求方式:(指定之后:就只能固定的请求方式可以访问资源dServlet!!!!)
默认情况:只要客户端发送请求的地址正确:任何请求方式都可以访问dServlet:@RequestMapping("login")
指定请求方式:
方法1:在路径设置注解中添加属性:method=""; eg:@RequestMapping("login",methods={RequestMethod.GET,RequestMethod.POST)
注解进阶:!方法2:在相应的方法上:加上对应的注解:eg:@GetMapping、@PostMapping、@PutMapping、@DeleteMapping
但是不能加到类上
如果不符合请求方式:会出现405异常;
*/
eg:
@RequestMapping("login")
public String login(){
return null;
}
@GetMapping("/o1") //使用注解设置提交方式:为Get:之后客户端在请求资源时就只能以get方式请求
public String o1(){
return null;
}
@PutMapping("/o2") //使用注解设置提交方式:为put:之后客户端在请求资源时就只能以put方式请求
public String o2(){
return null;
}
}
2.2如何接收参数(重点!!!)
接收 来自前端(浏览器)传过来的 地址上的参数(参数有多种)!!!!!
我们重点学习:如何接收前端发送的各种类型的参数;!!!!!!
2.2.1.param和json
(1)param和JSON的对比:
1.param参数形式:
key=value & key=valeu
2.json参数形式:
{key:value,key:value}
3.param 和 JSON 两种参数形式的比较:
(1)参数编码:
param:Ascall编码; JSON:UTF-8;
(2)参数顺序:
param:参数没有顺序;
JSON:参数有顺序;
(3)数据类型:
param:只支持字符串类型; eg:在前端传来参数:name=张三&age=18 最终都会转换成字符串类型;
json:可以装多种;
(4)嵌套性:
param:无嵌套:只有1层
json:可以无限嵌套,只要符号json的格式;
(5)可读性:
简单的参数:param读起来较为简单
复杂的参数:json读起来清晰;
注意:一般使用JSON,且JSON格式传递要求请求方式必须是POST;!!!!!!!!!
2.2.2:param方式如何接收参数:
(2)如何接收前端发送的Json和param类型的参数;
接收方式有三种:
1.直接接收:
2.注解指定
3.特殊值
4.使用实体类对象接收;
/*
1.直接接收:(直接接值)
eg:!!!当前端发送:/param/data?name=root&age=18
如何接收:handler方法的形参列表 填写对应名称的参数即可! 形参参数名= 前端访问的参数名 即可;
1.名称相同; 2.可以不传递,不会报错;
*/
//handler方法:
@RequestMapping("/data") //将handler注册到handlerMapper + 外部访问handler的地址;
@ResponseBody
public String data(String name,int age){
System.out.println("name = " + name + ", age = " + age);
return "name =" +name+"age ="+age;
}
/*
2.注解指定:(注解接值)
@RequestParam:放在形参列表,用来指定:请求参数名 或者 是否必须传递 或者非必须传递情况下设置默认值;
用法:@RequestParam(value="指定请求参数名":如果新参名称和请求参数名一样可以省略;如果指定了value,原来的参数就会失效,只有传入指定的参数才会生效:
required=false:前端是否必须传递此参数,默认是必须传,否则报400异常
defaultValue="1":当为false时非必须传递时,可以设置默认值;)
eg: !!当前端发送:/param/data1?account=root&page=1;
要求:account必须传递,page可以不传递,如果不传递默认值就是1
*/
@RequestMapping("/data1")
@ResponseBody
public String data1(@RequestParam(value = "account") String name, //value:指定参数名,请求参数必须传account!!!!
@RequestParam(required = false,defaultValue = "1") int page){
//required=false(代表不是必须传递)和defaultValue(代表默认值)一定是一块出现的
System.out.println("name = " + name + ", page = " + page);
return "name = " + name + ", page = " + page;
}
/*
3.一名多值:(集合接值)
如何接收参数:直接在方法形参处:使用“集合”进行接收;
eg:!!当前端传来: /param/data2/hobby=唱& hobby=跳&hobby=rap
注意:在形参处:必须加上@RequestParam!!!!!!!!!
*/
@RequestMapping("/data2")
@ResponseBody
public String data2(@RequestParam List<String> hbs){
System.out.println("hbs = " + hbs);
return "ok";
}
/*
4.!!!!!!!使用实体对象接值:
eg:前端传:/param/data3?name=二狗子&age=18
如何接收参数:准备一个有对应的属性、get/set方法的实体类即可; 然后在handler方法形参中传入实体类对象即可;
注意:实体类的属性名一定要等于前端传入的参数名!!!
*/
@RequestMapping("/data3")
@ResponseBody
public String data3(User user){
System.out.println("user = " + user);
return user.toString();
}
}
2.2.3:路径参数接收:
eg:原来:/user/login?account=root&password=123456
路径传参:/user/login/root/123456:这个root和"123456"本身已经是参数了;
实现步骤:
1.设置动态路径:即使用@RequeatMapping({key1},{key2});
2.接收动态路径参数 :在方法形参中必须使用@PathVariable注解指定参数
因为(String username,String password)是用来接收Param格式的参数的!!!!!
而@PathVariable才是用来接收路径参数的!!!!!!!!;
路径参数演示:
eg: /path/root/密码
*/
@Controller
@RequestMapping("path")
@ResponseBody
public class PathController {
//handler方法:
//1.设置动态路径:{key}
@RequestMapping("{account},{password}")
public String login(@PathVariable(value = "account") String username, @PathVariable String password){
//2.路径参数的接收:必须使用:@PathVariable注解在形参来指定接收参数
System.out.println("username = " + username + ", password = " + password);
return "username = " + username + ", password = " + password;
//访问时:/path/root/123
}
2.2.4;json参数接收:
学习目标:
:在前端发送json格式的请求:我们如何在后端进行接收;
Json格式的数据:前端必须使用 “ Post ”的方式进行请求;
Json是通过体进行发送的
1. Json:是在JS中的一种“ 对象 ”表达方式; 我们使用对应的 “ 实体类 ”进行接收就行了;
2.在handler方法形参处:使用@Request注解指定参数(因为json是放到请求体中的!!!)
3.在配置类最上方:加@EnableWebMvc //给handlerAdapter配置json转换器
注意:@EnableWebMvc: 添加HandlerMapping、HandlerAdapter、以及json转换器
所以加上这个注解之后:我们就不需要在配置类中:写HandlerMapping、HandlerAdapter了!!!!!!!!!
eg:
/handler
@PostMapping("data")
public String data(@RequestBody Person person){
//因为是Json格式的参数:使用@RequestBody注解 指定参数
System.out.println("person = " + person);
return person.toString();
//最终:我们:在postman:
//会415异常:因为java原生的api只支持路径参数和param参数;
//因为json是前端的格式
/*、
解决方法:
1.导入json的依赖
2.handlerAdapter配置json转换器
在配置类上加上:@EnableWebMvc (//给handlerAdapter配置json转换器)
*/
}
2.3如何接收Cookie数据
@Controller
@RequestMapping("cookie")
@ResponseBody
public class CookieController {
//handler:
//(2)前端携带cookie来访问,后端接收Cookie;
//即在handler方法中:使用@CookieValue注解指定参数
@RequestMapping("data")
public String data(@CookieValue(value = "cookieName") String value){
System.out.println("value = " + value);
return "value = " + value;
}
//(1)存Cookie@:即后端得先创造1个cookie,交给/存到前端; 之后前端才可以拿着cookie访问资源
@GetMapping("save")
public String save(HttpServletResponse response){ //response对象直接在形参处声明即可,之后下方就可以直接使用了!!
/
Cookie cookie=new Cookie("cookieName","root"); //a:创建cookie对象
response.addCookie(cookie); //b:将cookie放入响应对象中,携带到客户端,下次再请求时就会带到后端
//后端交给前端,所以是:放入响应对象中来传给前端
return "ok";
}
}
2.4接收请求头数据:
使用@RequestHeader("要接受的名称")指定handler形参!!
@Controller
@ResponseBody
@RequestMapping("header")
public class HeaderController {
//handler
@GetMapping("data")
public String data(@RequestHeader("Host") String host){
//接收请求头:在形参处:使用@RequestHeader("Host")注解指定参数:代表接收Host头,然后赋值给String host
System.out.println("host = " + host);
return host;
}
2.5原生对象如何获取:
@Controller
public class ApiController {
//第二种:声明全局变量:全局注入
@Autowired //ioc容器获取对应类型的实体对象,并自动装配;
//在程序启动时:ServletContext会自动装入ico容器
private ServletContext servletContext;
//第一种:
//先直接在形参处声明
//然后在下方:直接使用原生对象即可
public void data(HttpServletResponse response,
HttpServletRequest request,
Session session){
//下方直接使相应的变量即可 eg:
RequestDispatcher s = request.getRequestDispatcher("s");
}
}
2.6如何获取共享域对象以及共享域对象的操作:
共享域:
常用的三个范围(请求域,会话域,共享域):
request:一次请求以及转发之内
session:一次会话之内:一个浏览器的多次请求
servletContext:整个项目;
共享域操作:
存:setAttribuet(key,"object value")
取:get..
更新:set.. :两次set相同的key会进行更新
删除:remover...;
获取共享域:
//获取共享域:
//(1)
//方法1:原生api:直接在形参处声明即可
public void data(HttpServletRequest request,
HttpServletResponse response, Session session){
}
//方法2:声明全局变量
//声明为全局变量:就拿到了
@Autowired
private ServletContext servletContext;
//(2)
//SpringMvc针对request提供了几种方式; (了解)
三SpringMvc如何简化数据响应:
响应数据:
即后端接收前端发送的数据之后,要将返回结果返回给前端:
返回结果一般有两种:
1.页面跳转(返回视图页面)
2.返回数据(一般是json)
public Object handler(简化请求参数){
调用业务方法
返回结果(1.页面跳转,2.返回数据(json));
return “ 简化响应前端数据 ”
}
3.1混合开发下handler如何快速返回模板页面:
3.2前后端分离下后端如何返回json数据(重点!!!!)
@ResponseBody:把返回的对应Json数据直接返回给客户端,而不去走视图页面;!!!
@Controller //加到ioc容器
@RequestMapping("json")
@ResponseBody //返回json的注解:可以添加到类/方法上
public class JsonController {
//handler
@ResponseBody //代表:把数据直接返回字符串,不找视图页面!!!
@GetMapping("data")
//1.接收json:直接将方法的返回值设为json对应的实体类!!!!!!!!!
public User data(){ //后端接收前端发送的json:
User user=new User();
user.setName("egz");
user.setAge(18);
return user; //user会在handlerAdapter种转为json字符串
}
//2.
@ResponseBody
@GetMapping("data1")
public List<User>data1(){
User user=new User();
user.setName("egz");
user.setAge(18);
List<User> users=new ArrayList<>();
users.add(user);
return users;
}
}
注意:1.要返回json:必须加上@ResponseBody注解:代表 数据直接放入响应体返回!不会走视图解析器;!!!!!!!!!
快速查找视图和 转发重定向就都不生效了;
2.@ResponseBody注解可以加到方法上,也可以加到类上;
3.如果这个类中:所有的方法都是返回json的,我们可以在类上添加:@RestController注解:=@Controller+@ResponseBody
3.3返回静态资源处理:
静态资源:html页面,图片...
默认情况下:无法访问静态资源,我们需要开启静态资源查找:
之后dispatcherServlet会去handlerMapping中去找有没有对应的handler,如果没有就访问静态资源;
在配置类中:
//开启静态资源处理 <mvc:default-servlet-handler/>
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
四:RESTFul风格设计和实战
4.1 RESTFul风格概述
背景:
客户端和java程序:通过Http协议进行交互
Http协议:
1.url【地址】
2.请求方式:get、post、put、delete
3.传递参数:param】json、path;
但是我们面临:每次该如何设计 url、请求方式、传递参数;
因此我们使用RESTFul:
(1)RESTFul:
RESTFul:是Http协议的标准使用方案和风格;!!!!!!!
它会教我们如何设计路径url,如何选择请求方式、如何设计参数传递(param、json、路径参数);!!!!!
(2)使用了RESTFul。就是RESTFul风格;
4.2:RESTFul:风格特点:
1.客户端和服务端之间的交互是无状态的,从客户端到服务端的每个请求都必须包含所必须的信息
2.交互的数据使用json!!!!!
RESTFul特点:
1每一个URI/url为是名词!!!;
2.要求你使用对应的“ 请求方式 ”来指定对应的动作:
eg:获取/查询操作:使用get
删除操作:使用delete请求方式
增加/保存操作:post
更新操作:put
注意:但是不要在url中加上crud动作,url中只包含名词!!!
eg: /CRUD/saveEmp -->:/../emp +使用get请求方式!!!!
总结:
RESTFul:根据具体的动作选择具体的请求方式:增删改查操作:选择对应的请求方式;
路径url只包含n即可;
4.3RESTFul 实战分析:!!!!!
分析:
学习如何选择请求方式、设计请求参数、请求路径:!!!!
(1)
没有请求体:
获取:get
删除:delete
这两种可以使用: /url +路径参数
/url ? +param
注意:使用get/delete 时
1.当参数是id标识时:,选择使用路径传递参数!!!
eg:根据id删除/查询数据:--->: /模块/id
2.当参数不是id,是范围参数时:,选择使用param传递参数!!!
eg: param key=value;
(2)
有请求体:
保存:post
修改:put
这两种可以使用:
/url + 路径参数
/url ? + param
请求体传参(json)!!!一般使用json!!!
注意:当使用post时:我们一般使用请求体json!!!!!
总结:!!!!!!!!!!!!!
第一步:选择对应的动作(请求方式):crud
第二步:看参数是什么:
第三步:路径:/模块;
结合案例!!!!!!!!!!;
五:SpringMvc其它扩展
5.1:全局异常处理机制:
5.1.1异常处理的两种机制:
1.编程式异常处理:
在代码中显示的编写处理异常的逻辑; eg:使用try-catch来捕获异常,然后再catch中编写特定的处理代码,或者再finally中执行一些清理操作;--》:即开发人员需要显示的进行异常处理,可读性较差;
2.声明式事务处理:将异常处理的逻辑从具体业务中提取出来,通过配置等方式进行统一管理;
-->:在声明式异常处理中,开发人员只需要为方法或类标注相应的注解(如 @Throws 或 @ExceptionHandler),就可以处理特定类型的异常。
5.1.2:声明式事务处理:
步骤:
1.声明一个全局异常处理类(全局异常处理器);:使用@RestControllerAdvice注解(底层是aop)
2.在里面写若干个异常处理方法handler:
在handler上通过@ExceptionHadler注解来指定对应的异常类型;
之后发生响应的异常就会调用对应的handler方法;
注意:@RestControllerAdvice注解:代表handler方法处理完之间返回字符串;