一、Spring两大核心
1**.IOC**与 DI
- 思想:IoC(Inverse of Control:控制反转)是一种设计思想,就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理。
- IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。
- 将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。
- IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件xml/注解即可,完全不用考虑对象是如何被创建出来的。
- IoC 是一个概念,是一种思想,其实现方式多种多样。Spring 框架使用依赖注入(DI)实现 IoC
- 定义: DI---Dependency Injection ,即 " 依赖注入 "。依赖注入 DI 是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。
- 通常,依赖注入可以通过三种方式完成,即:构造函数注入,setter 注入,接口注入。在 Spring Framework 中,仅使用构造函数和 setter 注入 。
- Spring IOC 作用:管理项目中的Java bean的生命周期
- 为什么需要:在项目运行阶段,程序中需要很多对象来完成整体业务
- 容器和代码之间的代码控制权反转,代码中不需要明文调用来方法得到对象, 只需要声明该类需要什么类型的对象即可
2.AOP
AOP:面向切面编程,实现在不修改源代码 的情况下给程序动态统一添加额外功能的一种技术
-
AOP的作用
-
AOP 采取横向抽取机制(动态代理),取代了传统纵向继承机制的重复性代码,其应用主要体现在事务处理、日志管理、权限控制、异常处理等方面。
-
主要作用是分离功能性需求和非功能性需求,使开发人员可以集中处理某一个关注点或者横切逻辑,减少对业务代码的侵入(拦截器---切入点),增强代码的可读性和可维护性。
-
简单的说,AOP 的作用就是保证开发者在不修改源代码的前提下,为系统中的业务组件添加某种通用功能。
-
-
Spring AOP的术语
- Spring AOP 通知分类
-
定义切点
-
通过execution函数来定义切点
-
语法:execution(访问修饰符 返回类型 方法名 参数 异常)
-
具体事例说明:(..):表示方法参数列表,其中..
表示任意数量和类型的参数。
- 匹配所有类public方法:execution(public * *(..))第一个*表示返回值 ..表示任意个任意类型的参数
- 匹配指定包下所有类所有方法: execution(* cn.xxx.dao.*.*(..)) 第一个想*表示忽略权限和返回值类型
- 匹配指定包下所有类所有方法:execution(* cn.xxx.dao..*(..))包含子包
- 匹配指定类所有方法: execution(* cn.xxx.service.UserService.*(..))
- 匹配实现特定接口所有类方法 : execution(* cn.xxx.dao.GenericDAO+.*(..))
- 匹配所有save开头的方法: execution(* save*(..))
- 匹配某个指定的方法: execution(* com.yh.dao.StudentService.save(..))
二、代理模式
1.静态代理
2.动态模式
2.1 JDK动态代理(组合,被代理类必须实现接口)
-
代码实现
- 定义接口
- 定义代理处理器
//正常执行业务逻辑
//作用是调用被代理对象的实际方法,但并不是调用被代理对象的所有方法。它只会调用当前被拦截的方法。
- result = method.invoke(proxyedObj, args);
- 声明代理工厂
- 方法测试
2.2 CGLIB动态代理(继承,被代理类不能被final修饰)
- 定义业务类
- 定义代理业务
- 代码测试
三、 拦截器
1.拦截器(Interceptor)是 Spring MVC 提供的一种强大的功能组件。它可以对用户请求进行拦截,并在请求进入控制器(Controller)之前handler、控制器处理完请求后、甚至是渲染视图后,执行一些指定的操作。
//正常执行业务逻辑
//作用是调用被代理对象的实际方法,但并不是调用被代理对象的所有方法。它只会调用当前被拦截的方法。
- result = method.invoke(proxyedObj, args);
2.在 Spring MVC 中,拦截器的作用与 Servlet 中的过滤器类似,它主要用于拦截用户请求并做相应的处理,例如通过拦截器,我们可以执行权限验证、记录请求信息日志、判断用户是否已登录等操作。
- 1.拦截器定义与逻辑代码
- preHandle() 返回值判断是否会进行后续操作,true会继续(不拦截),false不会继续(进行拦截)
java
@Component
public class Interceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("-----preHandle:返回值判断是否会进行后续操作");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("--------postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("--------afterCompletion");
}
}
-
- 配置拦截器
-
拦截器的执行流程
-
当请求的路径与拦截器拦截的路径相匹配时,程序会先执行拦截器类(MyInterceptor)的 preHandle() 方法。若该方法返回值为 true,则继续向下执行 Controller(控制器)中的方法,否则将不再向下执行;-
控制器方法对请求进行处理;
-
调用拦截器的 postHandle() 方法,此时我们可以对请求域中的模型(Model)数据和视图做出进一步的修改;
-
通过 DispatcherServlet 的 render() 方法对视图进行渲染;
-
调用拦截器的 afterCompletion () 方法,完成资源清理、日志记录等工作。
-
-
多个拦截器的执行流程。
-
在大型的企业级项目中,通常都不会只有一个拦截器,开发人员可能会定义许多不同的拦截器来实现不同的功能。
-
四、springmvc 运行原理
Spring MVC 使用 MVC 架构模式的思想,将 Web 应用进行职责解构,把一个复杂的 Web 应用划分成模型(Model)、控制器(Contorller)以及视图(View)三层,有效地简化了 Web 应用的开发,降低了出错风险,同时也方便了开发人员之间的分工配合
用户通过浏览器发起一个 HTTP 请求,该请求会被 DispatcherServlet(前端控制器)拦截;
DispatcherServlet 调用 HandlerMapping(处理器映射器)找到具体的处理器(Handler)及拦截器,
HandlerMapping将Handler以 HandlerExecutionChain 执行链的形式返回给 DispatcherServlet。
DispatcherServlet 将执行链返回的 Handler 信息发送给 HandlerAdapter(处理器适配器);
HandlerAdapter 根据 Handler 信息找到并执行相应的 Handler(即 Controller 控制器)对请求进行处理;
Handler 执行完毕后会返回给 HandlerAdapter 一个 ModelAndView 对象(Spring MVC 的底层对象,包括 Model 数据模型和 View 视图信息);
HandlerAdapter 接收到 ModelAndView 对象后,将其返回给 DispatcherServlet ;
DispatcherServlet 接收到 ModelAndView 对象后,会请求 ViewResolver(视图解析器)对视图进行解析;
ViewResolver 解析完成后,会将 View 视图并返回给 DispatcherServlet;
DispatcherServlet 接收到具体的 View 视图后,进行视图渲染,将 Model 中的模型数据填充到 View 视图中的 request 域,生成最终的 View(视图);
视图负责将结果显示到浏览器(客户端)。
-
Spring MVC 常用(核心)组件
-
Spring MVC 的常用组件共有 5 个,它们分别是: DispatcherServlet(前端控制器)、HandlerMapping(处理器映射器)、HandlerAdapter(处理器适配器)、Handler(处理器)、ViewResolver(视图解析器)
-
五、springmvc异常处理机制
-
如果程序发生异常,Spring MVC 会按照 ExceptionHandlerExceptionResolver → ResponseStatusExceptionResolver → DefaultHandlerExceptionResolver 的顺序,依次使用这三个异常处理器对异常进行解析,直到完成对异常的解析工作为止。
-
@ExceptionHandler 注解(局部处理)
-
全局异常处理
- @ExceptionHandler 方法定义在一个使用了 @ControllerAdvice 注解的类中。使用 @ControllerAdvice 注解的类可以包含多个不同的带有 @ExceptionHandler 注解的方法
六、相关注解
1、@Controller 与 @RestController 区别:
@Controller:返回值优先作为地址,如果要返回json,需要添加@ResponseBody
- @Controller是Spring MVC中用于定义传统Web控制器的注解。它通常与视图技术(如JSP、Thymeleaf)一起使用,返回一个视图名称,由视图解析器解析并渲染视图。
特点:
- 返回视图名称:@Controller 通常返回一个地址(如
"home"
),由视图解析器解析为具体的视图实现(如JSP、Thymeleaf模板)。 - 使用@RequestMapping:方法上通常使用@RequestMapping注解来映射请求。
- 使用
@ResponseBody
:如果需要返回JSON、XML等数据,可以在方法上添加@ResponseBody注解,将返回值直接写入HTTP响应体。
@RestController:返回值类型json
@RestController 是Spring 4.0引入的一个组合注解,它结合了@Controller
和@ResponseBody
的功能。主要用于构建RESTful Web服务,返回JSON、XML等数据,而不是视图。
特点
- 直接返回数据 :@RestController 的方法默认返回数据,而不是视图名称。返回值会自动转换为JSON或XML格式,并写入HTTP响应体。
- 简化注解 :不需要在每个方法上添加
@ResponseBody
注解,简化了代码。 - 适用于RESTful服务 :非常适合构建RESTful Web服务,返回纯数据。
2. JSON 数据转换
-
Spring MVC 为我们提供了两个十分重要的与 JSON 格式转换相关的注解,它们分别是 @RequestBody 和 @ResponseBody。
3. Spring MVC实现RESTful
-
在 Spring MVC 中,我们可以通过 @RequestMapping +@PathVariable 注解的方式,来实现 RESTful 风格的请求。
-
通过@RequestMapping 注解的路径设置
-
当请求中携带的参数是通过请求路径传递到服务器中时,我们就可以在 @RequestMapping 注解的 value 属性中通过占位符 {xxx} 来表示传递的参数
-
@RequestMapping("/testRest/{id}/{username}")
-
value(路径) 属性中占位符的位置应当与请求 URL 中参数的位置保持一致,否则会出现传错参数的情况。
-
-
通过 @PathVariable 注解绑定参数
- 我们可以在控制器方法的形参位置通过 @PathVariable 注解,将占位符 {xxx} 所表示的参数赋值给指定的形参。
java
@RestController
//处理全局的异常
@RequestMapping("staff")
public class StaffController {
@GetMapping("staff")
public CommonResult getList(Staff staff){
List<Staff> list =null;
System.out.println("获取数据");
return CommonResult.success(list);
}
@PostMapping("staff")
public CommonResult addStaff(Staff staff){
System.out.println("新增数据");
return CommonResult.success();
}
@PutMapping("staff")
public CommonResult update(){
System.out.println("编辑数据");
return CommonResult.success();
}
@DeleteMapping("staff/{id}")
public CommonResult delStaff(@PathVariable int id){
System.out.println("删除数据"+id);
return CommonResult.success();
}
@GetMapping("ex")
public CommonResult ex(){
System.out.println("+++++++++++++++++");
int a=12/0;
return CommonResult.success();
}
@ExceptionHandler(Exception.class)
@ResponseBody
public CommonResult exh(){
System.out.println("----------------");
return CommonResult.success(200,"稍有问题");
}
}
七、接收前端的参数
接收前端的参数 方法的参数名称和前台传递的参数名一样
(一)、获取表单数据
1. Map接收(非常灵活,但不严谨,有安全问题)
2.使用封装对象来接收参数 程序当中只接收我们所需要的数据
(二)、获取地址栏上的参数
-
查询参数 : 从URL的查询参数中获取值,使用
@RequestParam
注解。@GetMapping("/users") public User getUserById(@RequestParam Long id) { // 从查询参数中获取id return userService.getUserById(id); }
请求示例:
GET /users?id=123
-
请求体 : 从HTTP请求体中获取值,使用
@RequestBody
注解。@PostMapping("/users") public User createUser(@RequestBody User user) { // 从请求体中获取User对象 return userService.createUser(user); }
请求示例:
POST /users
,请求体中包含User对象的JSON数据。
3.加 @PathVariable
注解
如果加 @PathVariable
注解,方法参数将从URL路径中获取值。
@GetMapping("/users/{id}")
public User getUserById(@PathVariable Long id) {
// 从URL路径中获取id
return userService.getUserById(id);
}
请求示例:GET /users/123
java
//@Controller 将返回值优先当做地址
//@RestController
//REST 请求资源状态转换
//get post put deldte
//get user/1 获取 user/get
//get user/......(参数) 新增 user/add
//delete user/1 删除 user/del?id=1
//put user...... 编辑 user/edit
@RestController
@RequestMapping("user")
public class EasyDController {
//接收前端的参数 方法的参数名称和前台传递的参数名一样
//一、获取表单数据
@RequestMapping("parama")
public String praamA(String name){
return "Stringmvc接收到的参数是:"+name;
}
//同时接收多个参数:2种方式
// 1. Map接收(非常灵活,但不严谨,有安全问题)
@RequestMapping("paramb")
//加注解:变成接收参数的容器,将参数注入到map里面,如果没有就认为是创建一个对象
public Map praamb(@RequestParam Map params){
return params;
}
//2.使用封装对象来接收参数 程序当中只接收我们所需要的数据
@RequestMapping("paramc")
public Staff paramc(Staff staff){
return staff;
}
//二、获取地址栏上的参数
@RequestMapping("paramd/{id}")
//获取地址栏上的参数
public String paramd(@PathVariable Integer id, HttpServletRequest request){
String username = request.getParameter("username");
return "接收到的参数是:"+id+"---username:"+username;
}
/*作用域对象:
page
HttpServletRequest
HttpSeesion(ServletContext)
application
*/
@RequestMapping("easyaa")
public String easyaa(){
return "easyaa method";
}
}
八、请求转发与重定向区别
/*请求转发:同一个服务器中不同的服务进行转发,
浏览器发送一个请求,可以转发到到本项目中受保护的资源(例如:WEB-INF)
(地址栏不发生变化) forward
转发是request对象执行forward方法进行转发
(默认是转发)
* 重定向: 可以在不同的服务器之间跳转,
浏览器发送多次请求对象
(地址栏发生变化) redirect
重定向是通过response对象通知浏览器重新访问,使用redirect来重定向*/
java
@Controller
public class EasyEController {
@RequestMapping("methoda")
public String methodA(){
System.out.println("------methodA");
//return "forward:/methodb";
return "redirect:/methodb";
}
@RequestMapping("methodb")
//将返回对象直接返回到响应体里面
@ResponseBody
public String methodB(){
System.out.println("------methodB");
return "this is methodB";
}
@RequestMapping("methodc")
public String methodC(){
return "index.jsp";
}
}