• day05-SpringBootWeb请求响应


    请求响应:

    • 请求(HttpServletRequest):获取请求数据
    • 响应(HttpServletResponse):设置响应数据

    BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。
    CS架构:Client/Server,客户端/服务器架构模式。
    在这里插入图片描述

    一、请求

    1 Postman

    Postman 是一款功能强大的网页调试与发送网页 HTTP 请求的 Chrome 插件。

    2 简单参数

    简单参数:在向服务器发起请求时,向服务器传递的是一些普通的请求数据。

    2.1 原始方式(仅做了解,在以后的开发中不会使用到)

    在原始的 Web 程序当中,需要通过 Servlet 中提供的 API:HttpServletRequest(请求对象),获取
    请求的相关信息。比如获取请求参数: Tomcat 接收到 http 请求时:把请求的相关信息封装到 HttpServletRequest 对象中

    在 Controller 中,我们要想获取 Request 对象,可以直接在方法的形参中声明 HttpServletRequest 对象。然后就可以通过该对象来获取请求信息:

    	//1. 简单参数
         //原始方式
        @RequestMapping("/simpleParam")
        public String simpleParam(HttpServletRequest request){
            //获取请求参数
            String name = request.getParameter("name");
            String ageStr = request.getParameter("age");
    
            //需要手动进行类型转换
            int age = Integer.parseInt(ageStr);
            System.out.println(name+ ":" + age);
            return "OK";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.2 SpringBoot方式

    如果是简单参数,参数名与形参变量名相同,定义同名的形参即可接收参数。

        //springboot方式
        @RequestMapping("/simpleParam")
        public String simpleParam(String name, Integer age){
            System.out.println(name+ ":" + age);
            return "OK";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    结论:不论是 GET 请求还是 POST 请求,对于简单参数来讲,只要保证请求参数名和 Controller 方法中的形参名保持一致 ,就可以获取到请求参数中的数据值。

    2.3 参数名不一致

    结论:运行没有报错。对于简单参数来讲,请求参数名和 controller 方法中的形参名不一致时,无法接收到请求数据。

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

    //    @RequestMapping("/simpleParam")
        public String simpleParam(@RequestParam(name = "name", required = false) String username, Integer age){
            System.out.println(username+ ":" + age);
            return "OK";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    @RequestParam 中的 required 属性默认为 true,代表该请求参数必须传递,如果不传递将报错。 如果该参数是可选的,可以将 required 属性设置为 false。

    3 实体参数

    3.1 简单实体对象

    简单实体对象:请求参数名与形参对象属性名相同,定义 POJO 接收即可
    在这里插入图片描述

        //2. 实体参数
        @RequestMapping("/simplePojo")
        public String simplePojo(User user){
            System.out.println(user);
            return "OK";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    public class User {
       private String name;
       private Integer age;
    }
    
    • 1
    • 2
    • 3
    • 4

    3.2 复杂实体对象

    复杂实体对象:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数。
    在这里插入图片描述

        @RequestMapping("/complexPojo")
        public String complexPojo(User user){
            System.out.println(user);
            return "OK";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    public class User {
        private String name;
        private Integer age;
        private Address address;
    }
    public class Address {
        private String province;
        private String city;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4 数组集合参数

    数组集合参数的使用场景:在 HTML 的表单中,有一个表单项是支持多选的(复选框),可以提交选择的多个值。
    在这里插入图片描述

    4.1 数组

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

    	//3. 数组集合参数
        @RequestMapping("/arrayParam")
        public String arrayParam(String[] hobby){
            System.out.println(Arrays.toString(hobby));
            return "OK";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.2 集合

    集合参数:请求参数名与形参集合名称相同且请求参数为多个,@RequestParam 绑定参数关系

        @RequestMapping("/listParam")
        public String listParam(@RequestParam List<String> hobby){
            System.out.println(hobby);
            return "OK";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5 日期参数

    日期参数:使用 @DateTimeFormat 注解完成日期参数格式转换,以及其 pattern 属性来设置日期的格式。
    在这里插入图片描述

    //4. 日期时间参数
        @RequestMapping("/dateParam")
        public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime){
            System.out.println(updateTime);
            return "OK";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    6 JSON参数

    JSON 参数:JSON 数据 键名 与形参对象 属性名 相同,定义 POJO 类型形参即可接收参数,需要使用 @RequestBody 标识
    在这里插入图片描述

    	//5. json参数
        @RequestMapping("/jsonParam")
        public String jsonParam(@RequestBody User user){
            System.out.println(user);
            return "OK";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    7 路径参数

    路径参数:通过请求 URL 直接传递参数,使用{…}来标识该路径参数,需要使用 @PathVariable 获取路径参数
    在这里插入图片描述

        //6. 路径参数
        @RequestMapping("/path/{id}")
        public String pathParam(@PathVariable Integer id){
            System.out.println(id);
            return "OK";
        }
    
        @RequestMapping("/path/{id}/{name}")
        public String pathParam2(@PathVariable Integer id , @PathVariable String name){
            System.out.println(id);
            System.out.println(name);
            return "OK";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    二、响应

    1 @ResponseBody

    类型:方法注解、类注解
    位置:Controller 方法上/类上
    作用:将方法返回值直接响应,如果返回值类型是 实体对象/集合 ,将会转换为 JSON 格式响应
    说明:@RestController = @Controller + @ResponseBody

    /**
     * 测试响应数据
     */
    @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;
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    2 统一响应结果

    前端:只需要按照统一格式的返回结果进行解析(仅一种解析方案),就可以拿到数据。

    统一的返回结果使用类来描述,在这个结果中包含:

    • 响应状态码:当前请求是成功,还是失败
    • 状态码信息:给页面的提示信息
    • 返回的数据:给前端响应的数据(字符串、对象、集合)
    /**
     * 统一响应结果封装类
     */
    public class Result {
        private Integer code ;//1 成功 , 0 失败
        private String msg; //提示信息
        private Object data; //数据 date
    
        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(Object data){
            return new Result(1, "success", data);
        }
        public static Result success(){
            return new Result(1, "success", null);
        }
        public static Result error(String msg){
            return new Result(0, msg, null);
        }
    
        @Override
        public String toString() {
            return "Result{" +
                    "code=" + code +
                    ", msg='" + msg + '\'' +
                    ", data=" + data +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    @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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    3 案例

    加载并解析 emp.xml 文件中的数据,完成数据处理,并在页面展示。
    在这里插入图片描述

    实现步骤

    1. 在 pom.xml 文件中引入 dom4j 的依赖,用于解析 XML 文件
    2. 引入资料中提供的解析 XML 的工具类 XMLParserUtils、对应的实体类 Emp、XML文件 emp.xml
    3. 引入资料中提供的静态页面文件,放在 resources 下的 static 目录下
    4. 编写 Controller 程序,处理请求,响应数据

    Springboot 项目的静态资源(html,css,js等前端资源)默认存放目录为:classpath:/static 、 classpath:/public、 classpath:/resources

    @RestController
    public class EmpController {
    
        @RequestMapping("/listEmp")
        public Result list(){
            //1. 加载并解析emp.xml
            String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
            System.out.println(file);
            List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
    
            //2. 对数据进行转换处理 - gender, job
            empList.stream().forEach(emp -> {
                //处理 gender 1: 男, 2: 女
                String gender = emp.getGender();
                if("1".equals(gender)){
                    emp.setGender("男");
                }else if("2".equals(gender)){
                    emp.setGender("女");
                }
    
                //处理job - 1: 讲师, 2: 班主任 , 3: 就业指导
                String job = emp.getJob();
                if("1".equals(job)){
                    emp.setJob("讲师");
                }else if("2".equals(job)){
                    emp.setJob("班主任");
                }else if("3".equals(job)){
                    emp.setJob("就业指导");
                }
            });
    
            //3. 响应数据
            return Result.success(empList);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    三、分层解耦

    1 三层架构

    在这里插入图片描述

    那其实我们上述案例的处理逻辑呢,从组成上看可以分为三个部分:

    1. 数据访问:负责业务数据的维护操作,包括增、删、改、查等操作。
    2. 逻辑处理:负责业务逻辑处理的代码。
    3. 请求处理、响应数据:负责,接收页面的请求,给页面响应数据。

    在这里插入图片描述

    1. Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
    2. Service:业务逻辑层。处理具体的业务逻辑。
    3. Dao:数据访问层(Data Access Object),也称为持久层。负责数据访问操作,包括数据的增、删、改、查。

    在这里插入图片描述

    2 分层解耦

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

    在这里插入图片描述

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

    3 IOC&DI

    3.1 IOC&DI入门

    ①. Service 层 及 Dao 层的实现类,交给 IOC 容器管理。
    ②. 为 Controller 及 Service 注入运行时,依赖的对象。
    ③. 运行测试。
    在这里插入图片描述

    3.2 IOC详解

    3.2.1 bean的声明

    要把某个对象交给 IOC 容器管理,需要在对应的类上加上如下注解之一:
    在这里插入图片描述

    注意事项:

    • 声明 bean 的时候,可以通过 value 属性指定 bean 的名字,如果没有指定,默认为类名首字母小写。
    • 使用以上四个注解都可以声明 bean,但是在 springboot 集成 web 开发中,声明控制器 bean 只能用 @Controller。
    3.2.2 组件扫描
    • 前面声明 bean 的四大注解,要想生效,还需要被组件扫描注解 @ComponentScan 扫描。
    • @ComponentScan 注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解 @SpringBootApplication 中,默认扫描的范围是启动类所在包及其子包
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(
        excludeFilters = {@Filter(
        type = FilterType.CUSTOM,
        classes = {TypeExcludeFilter.class}
    ), @Filter(
        type = FilterType.CUSTOM,
        classes = {AutoConfigurationExcludeFilter.class}
    )}
    )
    public @interface SpringBootApplication {
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3.3 DI详解

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

    通过以下几种方案来解决:

    1. @Primary
    2. @Qualifier
    3. @Resource
    @Primary
    @Service
    public class EmpServiceA implements EmpService {
    }
    
    • 1
    • 2
    • 3
    • 4
    @RestController
    public class EmpController {
        @Autowired    
        @Qualifier("empServiceA")
        private EmpService empService ;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    @RestController
    public class EmpController {
        @Resource(name = "empServiceB")
        private EmpService empService ;
    
    • 1
    • 2
    • 3
    • 4

    @Autowird 与 @Resource的区别

    1. @Autowired 是 spring 框架提供的注解,而 @Resource 是 JDK 提供的注解
    2. @Autowired 默认是按照类型注入,而 @Resource 是按照名称注入
  • 相关阅读:
    SQL Server 2014安装笔记
    【机器学习技巧】回归模型的几个常用评估指标(R2、Adjusted-R2、MSE、RMSE、MAE、MAPE)及其在sklearn中的调用方式
    2022-5月报
    DDU框架学习之路
    Linux
    软件测试自学还是报班好?
    矩阵分析与应用+张贤达
    机器学习期中考试
    Docker实战技巧(一):常用命令与最佳实践
    C#基础入门教程-简介和环境
  • 原文地址:https://blog.csdn.net/yirenyuan/article/details/136485678