一、工作原理
第一步:发起请求到前端控制器(DispatcherServlet),前端控制器请求HandlerMapping查找 Handler
第二步:处理器映射器HandlerMapping向前端控制器返回Handler
第三步:前端控制器调用处理器适配器去执行Handler , 处理器适配器去执行Handler
第四步:Handler执行完成给适配器返回ModelAndView , 处理器适配器向前端控制器返回ModelAndView
第五步:前端控制器请求视图解析器去进行视图解析 , 视图解析器向前端控制器返回View
第六步:前端控制器进行视图渲染 , 前端控制器向用户响应结果
二、注解与作用
@Controller :将一个类标记为处理程序,并将其注册为一个Bean,加入到Spring的IoC容器中。
@RequestMapping : 用于将请求URL映射到处理程序的方法上。通过在方法上添加@RequestMapping注解,我们可以指定处理特定URL的方法
@PathVariable :指定接收路径参数
@RequestParam :用来设置参数是否必须传递,默认必须传递,不传递需要设置默认值 @RequestBody : 用来指定接收json参数类型
@ResponseBody :方法的返回值将直接作为响应体返回给客户端,而不是通过视图解析器解析为视图。通常用于返回JSON或XML格式的数据
三、参数接收
1、param参数接收 :@RequestParam 用来设置参数是否必须传递
@Controller
@RequestMapping("param")
public class ParamController {
//直接接收
// /param/data?name=root&age=18
// 形参列表,填写对应名称的参数即可! 请求参数名 = 形参参数名即可!
// 1. 名称相同 2.可以不传递 不报错
@RequestMapping("data")
@ResponseBody
public String data(String name,int age){
System.out.println("name = " + name + ", age = " + age);
return "name = " + name + ", age = " + age;
}
@GetMapping("data1")
@ResponseBody
public String data1(@RequestParam(value = "account") String username,
@RequestParam(required = false,defaultValue = "1") int page){
System.out.println("username = " + username + ", page = " + page);
return "username = " + username + ", page = " + page;
}
//特殊值
// 一名多值 key=1&key=2 直接使用集合接值即可
//param/data2?hbs=吃&hbs=玩&hbs=学习
//不加注解@RequestParam 将 hbs对应的一个字符串直接赋值给集合! 类型异常!
//加了注解,经理就会将集合 add加入对应的字符串
@GetMapping("data2")
@ResponseBody
public String data2(@RequestParam List<String> hbs){
System.out.println("hbs = " + hbs);
return "ok";
}
//使用实体对象接值 用户注册(用户的信息) -》 对应的实体类 -》 插入到数据库 表
//param/data3?name=二狗子&age=18 准备一个对应属性和get|set方法的实体类即可! -> 形参列表声明对象参数即可!
@RequestMapping("data3")
@ResponseBody
public String data3(User user){
System.out.println("user = " + user);
return user.toString();
}
}
2.路径参数:默认是接收param参数 要用@PathVariable来指定接收路径参数
3、json参数接收:要用@RequestBody来指定接收json参数
@RequestMapping("json")
@Controller
@ResponseBody
public class JsonController {
@PostMapping("data")
public String data(@RequestBody Person person){
System.out.println("person = " + person);
return person.toString();
}
@PostMapping("data1")
public Person data1(@RequestBody Person person){
System.out.println("person = " + person);
return person;
}
}
四、页面跳转
1.快速返回逻辑视图 , 在配置类重写configureViewResolvers方法,设置jsp的前后缀,方法的返回值对应视图解析器的名称就行
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/",".jsp");
}
2、转发和重定向:转发 加上forward 重定向 加上redirect
@GetMapping("forward")
public String forward(){
System.out.println("JspController.forward");
return "forward:/jsp/index";
}
@GetMapping("redirect")
public String redirect(){
System.out.println("JspController.redirect");
return "redirect:/jsp/index";
}
3、返回json数据
4、静态资源访问 :在配置类重写configureDefaultServletHandling方法,来开启静态资源访问
五、restful风格
Restful风格的请求是使用“url+请求方式”**表示一次请求目的的,HTTP 协议里面四个表示操作方式的动词如下:
- GET:用于获取资源
- POST:用于新建资源
- PUT:用于更新资源
- DELETE:用于删除资源
六、扩展
1、全局异常处理
全局异常处理通常是通过使用@ControllerAdvice注解和@ExceptionHandler注解来实现的。这样可以确保当控制器层抛出异常时,有一个集中的处理机制来捕获并处理这些异常
全局异常类代码:
@RestControllerAdvice //@ResponseBody 直接返回json数据
public class GlobalExceptionHandler {
//发生异常 -> @ControllerAdvice 全局异常类 -> @ExceptionHandler 指定异常的类型,在里面写异常处理
@ExceptionHandler(ArithmeticException.class)
public Object ArithmeticException(ArithmeticException e){
String message = e.getMessage();
System.out.println("message = " + message);
return message;
}
@ExceptionHandler(Exception.class)
public Object Exception(Exception e){
String message = e.getMessage();
System.out.println("message = " + message);
return message;
}
}
2、拦截器
拦截器需要实现HandlerInterceptor
接口或继承HandlerInterceptorAdapter
类。HandlerInterceptor
接口定义了三个方法:
preHandle
:在Controller方法执行之前调用。如果返回true
,则继续向下执行(到下一个拦截器或处理器);如果返回false,则中断执行流程。postHandle
:在Controller方法执行之后,但在视图渲染之前调用。afterCompletion
:在整个请求完成之后调用,也就是在视图渲染之后。这里可以进行资源清理工作。
public void addInterceptors(InterceptorRegistry registry) {
//方案一,默认全部拦截
// registry.addInterceptor(new MyInterceptor());
//方案二,指定拦截
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/user/**");
//方案三 指定放行 不拦截
// registry.addInterceptor(new MyInterceptor()).excludePathPatterns("/user/**");
}