【JavaWeb-Spring boot】学习笔记

目录

<<回到导览

Spring boot

Spring boot官网

简介:Spring Boot 基于Spring,简化了配置,降低的入门难度,可以帮助我们非常快速的构建应用程序、简化开发、提高效率

需求:使用 SpringBoot 开发一个web应用,浏览器发起请求 /hello后,给浏览器返回字符串 "Hello World ~"

  1. 创建spring boot项目(保证网络间接正常)

  2. 删除一些暂时不用的文件

  3. 在包下创建文件

  4. 编写这个文件

    java 复制代码
    // 请求处理类
    @RestController
    public class HelloController {
        // 表名这个请求处理类,处理的是"/hello"
        @RequestMapping("/hello")
        public String Hello() {
            System.out.println("Hello World");
            return "Hello World!!!";
        }
    }

    运行启动类(SpringDemoApplication)

  5. 访问服务

    访问http://localhost:8080/hello或者http://127.0.0.1:8080/hello

每访问一次这个服务,控制台还会打印一次Hello World

1. http协议

概念:Hyper Text Transfer Protocol, 超文本传输协议,规定了浏览器和服务器之间数据传输的规则。

特点:

  1. 基于TCP协议:面向连接,安全
  2. 基于请求-响应模型的:一次请求对应一次响应
  3. HTTP协议是++无状态++ 的协议:对于事务处理没有记忆能力。每次请求-响应都是独立的。
    • 缺点:多次请求间不能共享数据。
    • 优点:速度快
1.1.请求协议
请求方式 请求参数位置 请求大小
GET 在请求行(没有请求体) 有大小限制
POST 在请求体 没有大小限制
  • GET请求

  • POST请求

1.2.响应协议

响应协议和POST请求有些相似,分为响应行、响应头、响应体,响应数据放在响应体里面

状态码 说明
1xx 临时状态码,表示请求已经接收,应该继续请求或者如果它已经完成则忽略它。
2xx 成功接收,处理已完成。
3xx 重定向到其他地方;让客户端再发起一次请求以完成整个处理。
4xx 客户端错误,责任在客户端。(如:请求了不存在的资源、客户端未被授权、禁止访问等。)
5xx 服务器错误,责任在服务端。(如:程序抛出异常等)。
常用状态码 解释
200 处理成功
302/304 location重定向/隐式重定向
400 客户端语法错误
403 服务器拒绝提供服务(没有权限)
404 请求资源不存在(url错误)
405 请求方式有误
500 服务器发生不可预期的错误
503 服务器尚未准备好处理请求

2.Tomcat

Web服务器是一个软件程序,对HTTP协议的操作进行封装,简化web服务器开发

作用:部署web项目,对外提供网上信息浏览服务

Tomcat:一个轻量级的web服务器,支持servlet、jsp等少量avaEE规范。也被称为web容器、servlet容器。

起步依赖:利用maven中依赖传递的特性,把开发某一个功能常见的依赖整合在一起(如web)

在spring boot web开发环境中,已经集成了Tomcat

2.1.请求
2.1.1.apifox

apifox官网:https://app.apifox.com/

apifox使用教程:https://www.bilibili.com/video/BV1Jc41147xC

在使用apifox之前要安装插件Apifox Browser Extension

尝试用apifox测试接口

2.1.2.简单参数

简单参数:参数名和变量名相同,定义形参即可接收参数

java 复制代码
@RestController
public class RequestController {
    @RequestMapping("/simpleParam")
    public String simpleParam(String name, int age) {
        System.out.println(name + ":" + age);
        return "OK";
    }
}

如果方法形参名称与请求参数名称不匹配,不能接收值,但是不会报错

这时,可以使用@RequestParam完成映射,但是该注解的required属性默认是true,代表++请求参数必须传递++

java 复制代码
@RestController
public class RequestController {
    @RequestMapping("/simpleParam")
    public String simpleParam(@RequestParam(name = "name") String username, int age) {
        System.out.println(username + ":" + age);
        return "OK";
    }
}
2.1.3.实体参数

实体参数:多个参数名和形参变量名相同,定义POJO接收即可

java 复制代码
@RestController
public class RequestController {
    @RequestMapping("/simplePojo")
    public String simpleParam(User user) {
        System.out.println(user);
        return "OK";
    }
}
java 复制代码
public class User{
    private String name;
    private int age;
    // Getter、Setter、toString
}
  • 示例

    为上面用户添加地址信息(包含省份和城市)

    java 复制代码
    @RestController
    public class RequestController {
        @RequestMapping("/complexPojo")
        public String complexPojo(User user) {
            System.out.println(user);
            return "OK";
        }
    }
    java 复制代码
    public class User{
        private String name;
        private int age;
        private Address address;
        // Getter、Setter、toString
    }
    java 复制代码
    public class Address {
        private String province;
        private String city;
        // Getter、Setter、toString
    }
2.1.4.数组集合参数
  • 数组参数:请求参数名与形参数组名称相同,定义数组类型形参即可接收参数

    java 复制代码
    @RestController
    public class RequestController {
        @RequestMapping("/arrayParam")
        public String arrayParam(String[] hobby) {
            System.out.println(Arrays.toString(hobby));
            return "OK";
        }
    }
  • 集合参数 :请求参数名与形参集合名称相同,通过@RequestParam绑定参数关系

    java 复制代码
    @RestController
    public class RequestController {
        @RequestMapping("/listParam")
        public String listParam(@RequestParam List<String> hobby) {
            System.out.println(hobby);
            return "OK";
        }
    }
2.1.5.日期参数

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

java 复制代码
@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";
    }
}
2.1.6.(重点)JSON参数

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

在上面的请求中,都是用的GET请求方式,++请求参数在请求行++ ,但利用json字符串传参要用POST请求方式,++请求参数在请求体++

  • 例如:

    json 复制代码
    {
        "name":"Tom",
        "age":18,
        "address":{
            "province":"四川",
            "city":"成都"
        }
    }
  • json参数传递

    java 复制代码
    @RestController
    public class RequestController {
        @RequestMapping("/jsonParam")
        public String jsonParam(@RequestBody User user) {
            System.out.println(user);
            return "OK";
        }
    }
2.1.7.路径参数

路径参数:通过URL直接传递参数,使用{}来标识该路径参数,需要使用@RequestMapping获取路径参数

java 复制代码
@RestController
public class RequestController {
    @RequestMapping("/pathParam/{id}")
    public String pathParam(@PathVariable Integer id) {
        System.out.println(id);
        return "OK";
    }
}
  • 传递多个路径参数

    java 复制代码
    @RestController
    public class RequestController {
        @RequestMapping("/pathParam/{id}/{uid}")
        public String pathParam(@PathVariable Integer id, @PathVariable Integer uid) {
            System.out.println(id + "," + uid);
            return "OK";
        }
    }
2.2.响应

@RestController注解包含了++@ResponseBody++ 注解++@Controller注解++

  • 统一响应结果:

    1. 响应码
    2. 提示信息
    3. 返回的数据
    java 复制代码
    // Result
    public class Result {
        private Integer code ;//1 成功 , 0 失败
        private String msg; //提示信息
        private Object data; //数据 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(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 +
                    '}';
        }
    }
  • 改写请求

    java 复制代码
    @RequestMapping("/simpleParam")
    public Result simpleParam(String name, int age) {
        System.out.println(name + ":" + age);
        return Result.success("Hello World");
    }
2.3.综合练习

获取员工数据,返回统一响应结果,在页面中渲染(相关资料可以在黑马官方公众号下载)

  1. 在pom.xml文件中引入dom4j的依赖,用于解析XML文件

    xml 复制代码
    <!-- 解析xml -->
    <dependency>
        <groupId>org.dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>2.1.3</version>
    </dependency>
  2. 引入资料中提供的解析XML的工具类XMLParserUtils、对应的实体类Emp、XML文件 emp.xml

  3. 引入资料中提供的静态页面文件,放在resources下的static目录下

  4. 编写Controller程序,处理请求,响应数据

    java 复制代码
    @RestController
    public class EmpController {
        @RequestMapping("/listEmp")
        public Result list() {
            // 1. 加载解析xml
            String file = "D:\\桌面\\Java\\Java(下)\\spring_demo\\src\\main\\resources\\emp.xml";
            List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
    
            // 2. 对数据进行转换处理
            empList.forEach(emp -> {
                String gender = emp.getGender();
                if("1".equals(gender)) {
                    emp.setGender("男");
                }else if("2".equals(gender)) {
                    emp.setGender("女");
                }
    
                String job = emp.getJob();
                if("1".equals(job)) {
                    emp.setJob("教师");
                }else if("2".equals(job)) {
                    emp.setGender("学生");
                }
            });
    
            // 3. 响应数据
            return Result.success(empList);
        }
    }
  • 尝试发送请求

  • 通过浏览器访问前端页面

3.三层架构

在上一节的综合练习中,代码的不同的业务逻辑写在了一起,导致代码复用性差,难以维护

为此设计了三层架构来优化

功能分类 对应层 说明
数据访问 controller(控制层) 接收前端发送的请求,对请求进行处理,并响应数据
逻辑处理 service(业务逻辑层) 处理具体的业务逻辑
接收请求、响应数据 dao(数据访问层,Data Access Object) 数据访问操作(包括增、删、改、查)

controller => service => dao (=>表示调用关系)

3.1.三层拆分

我们将上面三部分的代码分别写到对应层,每个对应层有一个接口(要做的事情),每个接口可以有若干个实现方案(实现类)

  1. 数据访问层(dao)

    java 复制代码
    // 接口
    public interface Empdao {
        // 获取员工列表
        public List<Emp> empList();
    }
    java 复制代码
    // 实现类
    public class EmpDaoA implements Empdao {
        @Override
        public List<Emp> empList() {
            // 1. 加载解析xml
            String file = "D:\\桌面\\Java\\Java(下)\\spring_demo\\src\\main\\resources\\emp.xml";
            List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
            return empList;
        }
    }
  2. 业务逻辑层(service)

    java 复制代码
    // 接口
    public interface EmpService {
        public List<Emp> empList();
    }
    java 复制代码
    // 实现类
    public class EmpServiceA implements EmpService {
        private Empdao empdao = new EmpDaoA();
    
        @Override
        public List<Emp> empList() {
            // 调用dao层接口
            List<Emp> empList = empdao.empList();
    
            // 2. 对数据进行转换处理
            empList.forEach(emp -> {
                String gender = emp.getGender();
                if("1".equals(gender)) {
                    emp.setGender("男");
                }else if("2".equals(gender)) {
                    emp.setGender("女");
                }
    
                String job = emp.getJob();
                if("1".equals(job)) {
                    emp.setJob("教师");
                }else if("2".equals(job)) {
                    emp.setGender("学生");
                }
            });
            return empList;
        }
    }
  3. 控制层(controller)

    java 复制代码
    @RestController
    public class EmpController {
        private EmpService empService = new EmpServiceA();
        @RequestMapping("/listEmp")
        public Result list() {
            // 3. 响应数据
            return Result.success(empService.empList());
        }
    }
3.2.分层解耦
  • 内聚:软件中各个功能模块内部的功能联系。
  • 耦合:衡量软件中各个层/模块之间的依赖、关联的程度。
  • 软件设计原则:高内聚低耦合

在上节的三层拆分中,三个层级耦合性比较高,我们要降低耦合性

控制反转(IOC):对象的创建控制器由程序自身转移到外部(容器),通过@Component注解实现
依赖注入(DI):容器为应用程序提供运行时所依赖的资源,通过@Autowired注解实现

  1. Service层、Dao层的实现类,交给IOC容器管理(控制反转)

    java 复制代码
    // Service层
    @Component
    public class EmpServiceA implements EmpService {
        private Empdao empdao;
        // ...
    }
    java 复制代码
    // Dao层
    @Component
    public class EmpDaoA implements Empdao {
        // ...
    }
  2. 为Controller层、Service层注入运行时依赖的对象(依赖注入)

    java 复制代码
    @RestController
    public class EmpController {
        @Autowired
        private EmpService empService;
    	// ...
    }
    java 复制代码
    // Service层
    @Component
    public class EmpServiceA implements EmpService {
        @Autowired  // 程序在运行时,IOC容器会提供该类型的bean对象,并赋值给该变量
        private Empdao empdao;
    	// ...
    }
3.3.补充
注解 声明 位置
@Component bean的基础注解 不属于以下三类时,用此注解(eg:工具类)
@Controller @Component的衍生注解 标注在控制器类上(@RestController注解已包括,一般不写)
@Service @Component的衍生注解 标注在业务逻辑类上
@Repository @Component的衍生注解 标注在数据访问类上(由于与mybatis整合,用的少)

了解:

  • 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
  • 前面声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描。
  • @ComponentScan注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解 @SpringBootApplication 中,默认扫描的范围是++启动类所在包及其子包++。
相关推荐
iOS技术狂热者6 小时前
wireshak抓手机包 wifi手机抓包工具
websocket·网络协议·tcp/ip·http·网络安全·https·udp
呆萌很7 小时前
SpringBoot+MyBatis Plus+PageHelper+vue+mysql 实现用户信息增删改查功能
spring boot
武昌库里写JAVA9 小时前
Golang的消息中间件选型
java·开发语言·spring boot·学习·课程设计
小小鸭程序员10 小时前
Spring Boot项目连接MySQL数据库及CRUD操作示例
java·spring boot·python·mysql·spring
字节源流11 小时前
【spring Cloud Netflix】OpenFeign组件
java·spring boot·后端
AntBlack11 小时前
都说 SpringBoot 启动慢 ,你知道慢在哪里吗?
java·spring boot·面试
爱的叹息13 小时前
Spring boot 中QPS(Queries Per Second)与 TPS(Transactions Per Second)详细对比
java·spring boot·后端
小小鸭程序员13 小时前
Spring Boot整合MyBatis-Plus实现CRUD操作教程
java·spring boot·python·mysql·spring
菲兹园长14 小时前
配置文件、Spring日志
java·spring boot·spring
爱的叹息15 小时前
Spring Boot 集成 Redis中@Cacheable 和 @CachePut 的详细对比,涵盖功能、执行流程、适用场景、参数配置及代码示例
spring boot·redis·后端