Spring(Day 17)

一、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");
    }
}
    1. 配置拦截器
  • 拦截器的执行流程


    当请求的路径与拦截器拦截的路径相匹配时,程序会先执行拦截器类(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等数据,而不是视图。

特点

  1. 直接返回数据 :@RestController 的方法默认返回数据,而不是视图名称。返回值会自动转换为JSON或XML格式,并写入HTTP响应体。
  2. 简化注解 :不需要在每个方法上添加@ResponseBody注解,简化了代码。
  3. 适用于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.使用封装对象来接收参数  程序当中只接收我们所需要的数据
(二)、获取地址栏上的参数
  1. 查询参数 : 从URL的查询参数中获取值,使用 @RequestParam 注解。

    @GetMapping("/users")
    public User getUserById(@RequestParam Long id) {
        // 从查询参数中获取id
        return userService.getUserById(id);
    }
    

    请求示例:GET /users?id=123

  2. 请求体 : 从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";
    }
}
相关推荐
好奇的菜鸟3 分钟前
Go语言中的引用类型:指针与传递机制
开发语言·后端·golang
所待.3837 分钟前
JavaEE之线程初阶(上)
java·java-ee
Winston Wood11 分钟前
Java线程池详解
java·线程池·多线程·性能
Alive~o.012 分钟前
Go语言进阶&依赖管理
开发语言·后端·golang
手握风云-15 分钟前
数据结构(Java版)第二期:包装类和泛型
java·开发语言·数据结构
许苑向上18 分钟前
Dubbo集成SpringBoot实现远程服务调用
spring boot·后端·dubbo
喵叔哟35 分钟前
重构代码中引入外部方法和引入本地扩展的区别
java·开发语言·重构
尘浮生41 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
郑祎亦1 小时前
Spring Boot 项目 myblog 整理
spring boot·后端·java-ee·maven·mybatis
不是二师兄的八戒1 小时前
本地 PHP 和 Java 开发环境 Docker 化与配置开机自启
java·docker·php