JAVA_WEB复习之请求响应

  1. 简单参数请求:原始的方法,我们需要通过servlet中提供的api,HttpServletRequest(请求对象),获取请求的相关信息。比如获取请求参数:当tomcat接收到请求时,它会把请求的信息封装httpservletrequest到对象中。
  2. 而在Springboot的环境,原始的API进行了封装,接收参数的形式更加简单。 如果是简单参数,参数名与形参变量名相同,定义同名的形参即可接收参数。
点击查看代码
@RestController
public class RequestController {
    // http://localhost:8080/simpleParam?name=Tom&age=10
    // 第1个请求参数: name=Tom   参数名:name,参数值:Tom
    // 第2个请求参数: age=10     参数名:age , 参数值:10
    
    //springboot方式
    @RequestMapping("/simpleParam")
    public String simpleParam(String name , Integer age ){//形参名和请求参数名保持一致
        System.out.println(name+"  :  "+age);
        return "OK";
    }
}
3.如果形参名与请求参数名不一致,则可以使用spring提供的@RequestParam注解来完成映射,也就是在方法前面加上@RequestParam 然后通过value属性执行请求参数名,从而完成映射。
点击查看代码
@RestController
public class RequestController {
    // http://localhost:8080/simpleParam?name=Tom&age=20
    // 请求参数名:name

    //springboot方式
    @RequestMapping("/simpleParam")
    public String simpleParam(@RequestParam("name") String username , Integer age ){
        System.out.println(username+"  :  "+age);
        return "OK";
    }
}
值得注意的是,该注解中的required属性默认为true的,代表该请求参数必须传递,如果不传递就会报错的,如果该参数是可选的,那么可以将required属性设置为false。
点击查看代码
@RequestMapping("/simpleParam")
public String simpleParam(@RequestParam(name = "name", required = false) String username, Integer age){
System.out.println(username+ ":" + age);
return "OK";
}
4.如果前端传入的参数过多,此时我们就可以引入实体类,将请求的数据封装到实体类中,值得注意的是,要想完成数据的封装,必须要得将请求参数名与实体类的属性名相同,必须对应, 5.下面则是比较复杂的实体类对象。指的即是,在一个实体类中有一个或多个属性,一个实体类中还嵌套其他的实体类,如下所示: ![](https://img2024.cnblogs.com/blog/3280652/202405/3280652-20240509104627798-110414460.png) 复杂实体类需要注意的是:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套实体类属性参数。 6.数组集合参数,当我们在前端页面表单进行多选情况时,可以提交多个值,那么就用到了数组集合了。那么多个值如何去提交,其实也是去一个一个提交的,后端接受的方式有两种,要么是数组,要么就是集合了。 定义数组时,只需注意参数名和形参数组名相同,且请求参数有多个,即可满足接受参数。
点击查看代码
@RestController
public class RequestController {
    //数组集合参数
    @RequestMapping("/arrayParam")
    public String arrayParam(String[] hobby){
        System.out.println(Arrays.toString(hobby));
        return "OK";
    }
}
7.集合参数: 当请求参数名与形参的集合对象名相同且请求参数为多个,@RequestParam 绑定参数关系,为什么要加注解呢,因为默认情况下,请求参数名相同的多个值,默认封装到数组中去的,如果要封装到集合中,就要使用该注解绑定参数关系。
点击查看代码
@RestController
public class RequestController {
    //数组集合参数
    @RequestMapping("/listParam")
    public String listParam(@RequestParam List<String> hobby){
        System.out.println(hobby);
        return "OK";
    }
}
8.那么这两个的区别在哪里呢,显而易见的,数组参数只能接受基本数据类型的数据传入,而集合不同,它既可以传入基本数据类型,还可以传入引用数据类型,可根据具体开发文档进行使用。 9.日期参数:在一些特殊情况下,有可能会涉及到日期类型的数据分装。 因为日期的格式多种多样(如:2022-12-12 10:05:45 、2022/12/12 10:05:45),那么对于日期类型的参数在进行封装的时候,需要通过@DateTimeFormat注解,以及其pattern属性来设置日期的格式。 这个注解的pattern属性指定了什么格式,前端的日期参数就必须按照什么格式传递,在后端的controller方法中,需要使用date类型或localdatetime类型,来封装传递的参数。
点击查看代码
@RestController
public class RequestController {
    //日期时间参数
   @RequestMapping("/dateParam")
    public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime){
        System.out.println(updateTime);
        return "OK";
    }
}
10.当我们开发时,如果需要传输比较复杂的参数时,前后端交互则会通过json格式的数据的传输。主要说明的就是,服务端在接受json数据时,需要使用实体类进行封装,json数据键名必须与形参对象属性名一致,定义对应的pojo数据即可接受参数,需要使用requestbody注解进行标识,该注解的作用就是,将json数据映射到形参的实体类中去,参数属性名必须保持一致啊!!
点击查看代码
@RestController
public class RequestController {
    //JSON参数
    @RequestMapping("/jsonParam")
    public String jsonParam(@RequestBody User user){
        System.out.println(user);
        return "OK";
    }
}
11.路径参数,什么是路径参数,传统意义上,即是请求参数放在请求体上传递,(这是post请求),或者跟在url后面,通过key=vlaue的形式传递,(这是get请求) 这是我们现在的开发,经常还是会直接使用url:
点击查看代码
xxxxxxxxxx http://localhost:8080/user/1        http://localhost:880/user/1/0
这被称为是路径参数,那么在springboot下,后端如何去接收数据呢? 前端:通过请求url直接传递参数 后端:使用{....}来标识该路径参数,需要使用@PathVariable获取路径参数
点击查看代码
xxxxxxxxxx @RestControllerpublic class RequestController {    //路径参数    @RequestMapping("/path/{id}")    public String pathParam(@PathVariable Integer id){        System.out.println(id);        return "OK";    }}
因为前端传递的路径是可变的,所以后端在接收参数时,使用“{key}”的方式来标记路径参数 该注解:1.获取到路径参数{id}2.把路径参数绑定到形参变量id上

那么如果需要传递多个路径参数该怎么办,很简单,前端正常输入路径参数{id},后端接收的时候/{id}/{id},然后在方法形参里面加上注解@pathvariable,每个形参前都需要加上,这样就可以自动绑定。

点击查看代码
@RestController
public class RequestController {
    //路径参数
    @RequestMapping("/path/{id}/{name}")
    public String pathParam2(@PathVariable Integer id, @PathVariable String name){
        System.out.println(id+ " : " +name);
        return "OK";
    }
}

12.响应
所谓有得必有失,那么有请求就有响应。Controller程序不仅可以接收数据,还可以进行响应数据。

在控制层中方法的返回值,return结果,它是如何响应给浏览器的呢?这个时候我们就用到了注解>** @ResponseBody。**
下面介绍一下这个注解的功能。
类型:方法注解、类注解
作用:将方法的返回值直接去响应给浏览器,如果范围值类型是实体对象或是集合的话,将会直接转换给json格式返回给浏览器。
但是我们所写的Controller方法中,只在类上添加了@RestController注解,方法添加了Requestmapping注解,并没有使用@ResponseBody注解,那么如何给浏览器进行响应呢?

点击查看代码
@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello(){
        System.out.println("Hello World ~");
        return "Hello World ~";
    }
}
原因就是@RestController是一个组合注解: @RestController = @Controller + @ResponseBody
点击查看代码
@Target({ElementType.TYPE})   //元注解(修饰注解的注解)
@Retention(RetentionPolicy.RUNTIME)  //元注解
@Documented    //元注解
@Controller   
@ResponseBody 
public @interface RestController {
    @AliasFor(
        annotation = Controller.class
    )
    String value() default "";
}
结论:当在类上添加@RestController就相当于添加了@ResponseBody注解。 当类上有@RestController注解或者@ResponseBody注解时,表示当前类下所有的方法返回值做为响应数据。 方法的返回值,如果是一个POJO或者是一个集合时,会先转换为JSON数据,再响应给浏览器。
点击查看代码
@RestController
public class ResponseController {
    //响应字符串
    @RequestMapping("/hello")
    public String hello(){
        System.out.println("Hello World ~");
        return "Hello World ~";
    }
    //响应实体对象
    @RequestMapping("/getAddr")
    public Address getAddr(){
        Address addr = new Address();//创建实体类对象
        addr.setProvince("广东");
        addr.setCity("深圳");
        return addr;
    }
    //响应集合数据
    @RequestMapping("/listAddr")
    public List<Address> listAddr(){
        List<Address> list = new ArrayList<>();//集合对象
        
        Address addr = new Address();
        addr.setProvince("广东");
        addr.setCity("深圳");

        Address addr2 = new Address();
        addr2.setProvince("陕西");
        addr2.setCity("西安");

        list.add(addr);
        list.add(addr2);
        return list;
    }
}

以上这些控制层里的方法,返回值比较杂乱,没有任何规范,当进行大型代码的开发时,多人合并开发的情况下,你所写的接口,别人看起来是不是不那么方便,项目就会变得难以维护,那么接下来就为大家介绍一下:

13.统一的响应结果
有了统一的响应结果,前端只需要按照统一的返回结果进行解析,就可以拿到比较规范的数据。
使用类来描述即是:

  • 响应状态码:当前返回的数据是否正确
  • 状态码信息:给页面进行反馈的提示信息
  • 返回来的数据:给前端响应的数据(字符串,对象,集合)

定义一个标准化的实体类,return的时候可以直接返回它。

点击查看代码
public class Result {
    private Integer code;//响应码,1 代表成功; 0 代表失败
    private String msg;  //响应码 描述字符串
    private Object data; //返回的数据

    public Result() { }
    public Result(Integer code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    //增删改 成功响应(不需要给前端返回数据)
    public static Result success(){
        return new Result(1,"success",null);
    }
    //查询 成功响应(把查询结果做为返回数据响应给前端)
    public static Result success(Object data){
        return new Result(1,"success",data);
    }
    //失败响应
    public static Result error(String msg){
        return new Result(0,msg,null);
    }
}
在控制层的方法中,只需return Result.success(),调用这个标准化实体类的方法,实体类有方法的空参和全参构造,可以根据需要进行返回。
点击查看代码
@RestController
public class ResponseController { 
    //响应统一格式的结果
    @RequestMapping("/hello")
    public Result hello(){
        System.out.println("Hello World ~");
        //return new Result(1,"success","Hello World ~");
        return Result.success("Hello World ~");
    }

    //响应统一格式的结果
    @RequestMapping("/getAddr")
    public Result getAddr(){
        Address addr = new Address();
        addr.setProvince("广东");
        addr.setCity("深圳");
        return Result.success(addr);
    }

    //响应统一格式的结果
    @RequestMapping("/listAddr")
    public Result listAddr(){
        List<Address> list = new ArrayList<>();

        Address addr = new Address();
        addr.setProvince("广东");
        addr.setCity("深圳");

        Address addr2 = new Address();
        addr2.setProvince("陕西");
        addr2.setCity("西安");

        list.add(addr);
        list.add(addr2);
        return Result.success(list);
    }
}

14.分层解耦
三层架构的引入,当我们在Controller层进行代码开发时,不论是XML数据,获取数据的代码,处理数据的逻辑的代码,给页面响应的代码全部都放在一起,都是控制层的方法中实现,小型项目开发还行,但是如果涉及到大型的开发时,就会变得非常臃肿,这个时候就引入了三层架构的拆分。
一般的项目进行开发时,会有如下的几种处理逻辑:

  • Controller :接受请求,响应数据,接受前端的所发送的请求,对请求进行处理,并且响应数据
  • Service : 进行逻辑处理;处理具体的业务逻辑,一般在它的实现类中实现。
  • Dao: 数据访问;也可以成为持久层,即时通过对数据库进行访问操作,包括数据的增、删、改、查。

基于以上三层架构的工作流程如下:

  • 首先则是前端发起请求,后端这边先由Controller层出来接受,再响应回去。
  • 此时控制层干什么,它就开始调用服务层来进行业务逻辑处理了,它处理完之后,把结果再返回给控制层。服务层再调用Dao层,在进行逻辑处理的过程中,需要使用Dao层中的数据,即就是从Dao层获取,Dao层操作文件中的数据,通过crud获得数据再给service层返回回去。

到这里了,相比已经知道了三层架构的优势了
即为以下几点:复用性强,便于维护,利于拓展。
15.耦合问题
什么是耦合问题?什么是内聚?什么是耦合?
内聚就是软件中各个功能模块中内部之间的关联
耦合即是衡量软件中各个层/模块之间的依赖程度,简而言之就是紧密程度。

高内聚指的是:一个模块中各个元素之间的联系的紧密程度,如果各个元素(语句、程序段)之间的联系程度越高,则内聚性越高,即 "高内聚"。
低耦合指的是:软件中各个层、模块之间的依赖关联程序越低越好。
这是程序开发的最优目的。
16.如何解耦
之前的时候,我们需要什么对象,new就行,但是如果要低耦合,让程序重用性更好,移植性更好,就不能再new一个实体类的对象。
那该怎么办呢,不能new对象,这很难受啊。此时,我们提供的解决思路就是:

  • 首先提供一个容器,容器中提供一对象(例如:EmpService对象)
  • Controller程序从容器中获取EmpService的对象
    要想实现解耦,就关联到Spring中的两个核心相关概念了
    首先则是控制反转,IOC。对象的创建控制权由程序自身转移到外部,这就是控制反转。也称为Spring容器。
    另外一个核心的概念即是依赖注入了,DI。当容器为程序提供运行时,所依赖的资源,称之为依赖注入。大白话来说,就是例如控制层在运行的时候需要EmpService层的对象了,那么Spring容器,也就是IOC容器就会为其提供并且注入EmpService对象。
    重点!!! IOC容器中创建、管理的对象,称之为bean对象。
    说了这么多,那么在实际开发过程中,如何去实现呢?
  • 首先删除Controller层、Service层中new对象的代码
  • Service层及Dao层的实现类,交给IOC容器管理
  • 为Controller及Service注入运行时依赖的对象
  • Controller程序中注入依赖的Service层对象
  • Service程序中注入依赖的Dao层对象
    删除了new对象的代码后,在Service层,以及Dao层的实现类中,使用@Component 注解,即可实现交给IOC容器管理。

然后就是在Controller以及Service注入运行时所需的依赖对象了。
@Autowired 注解,有了它,- 就可以实现程序运行时IOC容器自动注入需要的依赖对象。

面试题 : @Autowird 与 @Resource的区别

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

以上所有都依据黑马java理解总结。

posted @   东三元  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示