请求响应

一,引言

Tomcat是Servlet服务器,它是无法直接的识别到我们SpringBoot写的Controller的,我们之所以可以使用SpringBoot直接写Controller是因为SpringBoot的一个前端控制器(DispatcherServlet)来充当Tomcat服务器和Spring程序之间的中间人

工作流程如下:

  1. tomcat接收到浏览器的http请求
  2. tomcat将http请求解析后发送给前端控制器
  3. 前端控制器将这个解析后的内容封装给HttpServletRequest中,然后发送给对应的Controller
  4. Controller将Http响应信息发送给前端控制器。
  5. 前端控制器将内容封装到HttpServletReponse然后发送给Tomcat
  6. Tomcat解析完这个响应后将响应发送给浏览器。

image-20231011142728723

前端控制器的继承体系如下图:

image-20231011142639978

因为他的最终父类有Servlet,所以前端控制器可以接收Tomcat。

二,请求

2.1 简单参数

简单参数就是URL中?后面的key=value这种参数,举例:

localhost:8080?name=张三&age=13

原始的web程序中,获取请求参数,需要通过HttpServletRequest 对象手动获取

@RestController
public class IndexController {
    
    @RequestMapping("/getSimpleParam")
    public String getSimpleArgs(HttpServletRequest request){
        String name=request.getParameter("name");
        String ageStr=request.getParameter("age");
        System.out.println("name="+name);
        int age=Integer.parseInt(ageStr);
        System.out.println("age="+age);
        return "ok";
    }
    
}

SpringBoot程序中,获取简单参数只需要:参数名与形参变量名相同,定义形参即可接收参数

@RestController
public class IndexController {
    @RequestMapping("/simpleParam")
    public String simpleparam(String name , Integer age){
        System.out.println(name+" : "+age);
        return "Ok";
    }
    
}

如果方法形参名称与请求参数名称不匹配,可以使用 @RequestParam 完成映射。

@RestController
public class IndexController {
    
    @RequestMapping("/simpleParam")
    public String simpleparam(@RequestParam(value="name") String userName , Integer age){
        System.out.println(userName+" : "+age);
        return "Ok";
    }
    
}

映射方法就是value=url参数里面的名字,在对应需要映射的形参前面加上这个注解即可。

  • 需要注意的是,@RequestParam中的required属性默认为true,代表该请求参数必须传递,如果不传递将报错。如果该参数是可选的,可以将required属性设置为false。即@RequestParam(value="name",require=false)

2.2 实体参数

简单实体对象请求参数名与形参对象属性名相同,定义POJO接收即可。

简单的来说,我们可以定义一个Java类来接受请求参数,即封装思想。只需要我们请求参数名和实体类的属性名保持一致即可。

image-20231011145827940

复杂实体对象:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数。

image-20231011150012885

2.3 数组集合参数

数组参数:请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数。

如图所示:

image-20231011150753638

集合参数:默认情况下他是封装到数组当中的,但是我们一般是封装到集合中的,通过添加注解@RequestParam来绑定参数关系。

使用方法如下图所示。

image-20231011151346470

2.4 日期参数

日期参数:使用 @DateTimeFormat 注解完成日期参数格式转换

image-20231011151933603

需要注意的是,如果你这个日期是封装到pojo类里面的,那么对应参数的上面也需要加上这个注解!

2.5 Json参数

JSON参数:JSON数据键名与形参对象属性名相同定义POJO类型形参即可接收参数,需要使用 @RequestBody 标识

image-20231011152508213

2.6 路径参数

路径参数:通过请求URL直接传递参数,使用...来标识该路径参数,需要使用 @PathVariable 获取路径参数

  • 传递单个:image-20231011152706791

  • 传递多个:image-20231011152808119

三,Restful api接口规范

在前后端进行数据交互的时候,我们需要统一数据的请求规范。

根据不同的http请求我们给定不同的操作:

  • GET(select):从服务器取出资源(一项或多项)。
  • POST(create):在服务器新建一个资源。
  • PUT(update):在服务器更新资源(客户端提供改变后的完整资源)。
  • PATCH(update):在服务器更新资源(客户端提供改变的属性)。
  • DELETE(delete):从服务器删除资源。

四,响应

image-20231011153101474

统一响应结果:在正常项目中,我们后端需要对响应的结果进行统一的响应,不能随意想响应什么就响应什么。

如下图:

image-20231011153433151

五,分层解耦

在上述代码中,我们将所有的代码都放在了Controller中,这个是不对的,不规范的,我们需要正确的对项目进行分层处理。

5.1 MVC三层架构

我们需要将代码分成三层架构:

image-20231011153836703

controller: 控制层,接收前端发送的请求,对请求进行处理,并响应数据

  • Controller层只需要创建响应的java类即可

service:业务逻辑层,处理具体的业务逻辑包括数据的增、删、改、查。

  • service层需要创建接口,然后里面创建接口的实现类。

dao:数据访问层(Data Access object)(持久层),负责数据访问操作。

  • Dao层只需要创建接口即可,因为Mybatis可以通过xml或者注解映射SQL语句。

5.2 解耦

软件设计原则:高内聚低耦合

  • 内聚:软件中各个功能模块内部的功能联系。
  • 耦合:衡量软件中各个层/模块之间的依赖、关联的程度。

在上述我们三层架构代码之中,层与层之间的调用需要通过创建对象的方式来调用相应层里面的方法,这样会让三层架构之间存在依赖关系。

  • 当我们Service层切换实现类的时候,Controller层也需要创建对应的实现类对象
  • IOC和DI的存在就是用来解除层与层之间的依赖关系,又叫解耦
  • 当我们解开耦合之后,Service层切换了实现类,Controller层不需要进行变动了。

5.2.1 IOC和DI介绍

控制反转:Inyersion 0f Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转.
依赖注入:Dependency lnjection,简称Dl。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。
Bean对象:IOC容器中创建、管理的对象,称之为bean。

image-20231012133717921


IOC&DI入门

  1. 将Service层,Dao层的实现类交给IOC容器管理。(IOC)

    只需要将注解@Component写到对应的实现类上即可,将当前类交给IOC容器管理,成为IOC容器中的Bean

  2. 为Controller和Service注入运行时所依赖的对象。(DI)

    假设Controller层调用Service层,那么在Controller层中创建Service层的对象的时候,不给他赋值而是加上@Autowired注解即可实现依赖注入,Service层注入Dao层也是如此。

    image-20231012134201673

5.2.2 IOC

Bean的声明:要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一。

image-20231012134518658

在IOC容器中,每一个Bean对象都有一个标识,可以在声明Bean的时候通过value值来指定这个名字。

@Service(value="bean的名字")
@Service("bean的名字")//value属性根据java注解规则,可以不写。

如果不指定,默认为首字母小写的类名。


Bean组件扫描:

  • 前面声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描
  • @ComponentScan注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解 @SpringBootApplication
    中,默认扫描的范围是启动类所在包及其子包。

解决方法:

  • 手动指定组件扫描位置。

    在启动类中上加上注解@ComponentScan({"指定包名"})

    这是一个字符串数组,你一旦手动指定扫描那么默认设置的就失效了,也需要你再次指定。

  • 按照SpringBoot规范,将代码放到启动类所在包及其子包。

5.2.3 DI

@Autowired注解,默认是按照类型进行,如果存在多个相同类型的bean,将会报出如下错误:

image-20231012135529773

解决方法:

  1. @Primary:设置Bean的优先级,想让哪个Bean生效就加上这个注解即可。

  2. @Qualifies:配合@Autowired注解,加上@Qualifies注解来指定生效的Bean对象。里面的值就是bean对象的名字。

    image-20231012135712064

  3. @Resource:单独使用@Resource来指定注入的bean对象。

    image-20231012135820510

@Resource 与 @Autowired区别

  • @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解
  • @Autowired 默认是按照类型注入,而@Resource默认是按照名称注入

posted @ 2024-07-09 15:48  wdadwa  阅读(25)  评论(0)    收藏  举报