【JavaEE】spring boot快速上手

news2024/11/24 22:31:32

SpringBoot快速上手

文章目录

  • SpringBoot快速上手
    • Maven
      • 会出现的一个官方bug
      • 创建完项目之后
      • 常用的的三个功能
      • 依赖管理
      • Maven仓库
        • 中央仓库
        • 本地仓库
        • 国内源配置
        • 私服
    • springboot项目创建
      • 什么是spring
      • spring boot项目的创建
      • Hello World
        • web服务器
    • SpringMVC
      • 什么是SpringWebMVC
        • 什么是MVC
      • SpringMVC
      • 学习Spring web mvc
        • 建立连接
          • @RequestMapping
      • 请求
        • 指定请求方式
        • 请求单个参数
        • 请求多个参数
        • 传递对象
        • 参数重命名
          • 设置参数为非必传的
        • 传递数组
        • 传递集合
        • 传递`JSON`数据
          • JSON与Javascript的关系
          • JSON 优点
        • 获取URL中的参数
        • 上传文件
        • 获取Cookie/Session
          • Cookie
          • Session
          • Cookie和Session的区别
          • 传统方式获取Cookie
          • SpringBoot获取Cookie
          • 传统方式获取Session
          • SpringBoot获取Session
        • 获取Header
          • 传统获取Header
          • springboot方式获取Header
      • 响应
        • 返回静态页面
          • `@RestContraller` 和 `@Controller`的区别
          • 路径问题
          • 一个项目部署多个服务
        • 返回数据@ResponseBody
        • 返回HTML片段
        • 返回JSON
        • 设置状态码
        • 设置Header
          • 设置Content-Type
          • 设置其他Header
  • 案例
    • 加法计算器
      • 前端代码
      • 后端代码
        • 接口定义
    • 用户登录
      • 前端代码
      • 后端代码
    • 留言板
      • 前端代码
      • 后端代码
        • lombok工具包介绍
    • 图书管理系统
      • 定义接口
      • MOCK
      • 应用分层
        • 命名规范
        • MVC和三层架构之间的关系
  • SpringMVC小结
    • 什么是springmvc
    • @RequestMapping
    • 请求
    • 响应
    • 注解总结
    • Cookie和Session

学习流程介绍:

  1. spring boot
  2. springmvc
  3. spring framework
  4. mybatis
  5. spring 源码

Maven

项目管理工具,idea中将他嵌入进来了

  1. 项目构建、打包
  2. 依赖管理

会出现的一个官方bug

就是当你创建maven项目的时候会卡死

那么怎么办呢?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

你只能先关闭原来项目,再重新去创建maven项目。

创建完项目之后

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建完maven项目之后,idea右边会出现一个maven的框

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

那么右键选择

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

就可以解决这个问题.

常用的的三个功能

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

clean:清理class文件(也就是清理缓存)

package:打包

install:在工作中常用于发布包到本地

依赖管理

通过poe.xml

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

依赖已经进来了.

  1. 会将当前的依赖引入到当前项目里面

  2. Maven Helper

    插件,可以查看依赖之间的关系

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Maven仓库

仓库:

  1. 本地仓库
  2. 远程仓库
    1. 中央仓库
    2. 私有仓库
中央仓库

中央仓库

中央仓库查询会有一定的滞后性

本地仓库

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

需要自己配置噢

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

国内源配置

找到setting.xml文件,在 mirrors 节点上,添加内容如下:

<mirror>
 <id>aliyunmaven</id>
 <mirrorOf>central</mirrorOf>
 <name>阿⾥云公共仓库</name>
 <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
 </mirror>

然后再设置好新项目的setting.建议找一个存储空间大的盘,像我一样设置(如上图).因为随着时间推移,外卖做的项目的数量变多,本地仓库中的setting文件的占用的内存也会越来越多.

还有就是建议命名不要用中文!

私服

企业开发中一些代码具有一定的私密性,所以企业会建立自己的私服(需要账号密码)


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

springboot项目创建

建议是申请教育版本的ideaa或者专业版的idea噢~

如果是社区版的idea,那么就需要你去下载spring 插件

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

别直接点击Install,除非你钱多~

插件地址

什么是spring

spring是一个非常好用的框架,快 简单 安全

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

spring是一个家族产品,在面试中提到spring,大多是指spring家族.

spring boot的诞生就是未来简化spring程序开发的


spring boot项目的创建

  1. 需要注意的是现在idea2023创建spring项目的时候,只有jdk17 jdk21,可以选择,这里我的解决办法是替换项目的源头,我们只知道IDEA页面创建Spring项目,其实是访问spring initializr去创建项目。故我们可以通过阿里云国服去间接创建Spring项目。将https://start.spring.io/或者http://start.springboot.io/替换为 https://start.aliyun.com/.即可解决这个问题.

  2. 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  3. 选择springboot版本,选择2.X版本,因为2.X使用的是JDK8,也不要选择snapshot版本.(不稳定版本)

    snapshot 程序有问题的话,可以修改,重新发包

    非 snapshot 是不能修改的,若需要修改,只能改版本号

  4. 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  5. 在这里插入图片描述

  6. 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    此处的测试代码,和测试人员无关,是开发人员的测试代码,

    开发人员先进行简单测试,测试完成之后再提交给测试人员.单元测试代码

  7. 项目启动

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Hello World

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建HelloController

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello(){
        return "hello, SpringBoot";
    }
}

然后再网页中输入localhost:8080/hello

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

web服务器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

常⻅的Web服务器有: Apache,Nginx, IIS, Tomcat, Jboss

SpringBoot 内置了Tomcat服务器, ⽆需配置即可直接运⾏

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Tocmat默认端⼝号是8080, 所以我们程序访问时的端⼝号也是8080


SpringMVC

本小节将会了解到的:

  1. 学习常见的Spring MVC Web注解
  2. 了解SPring MVC来完成基础功能开发
  3. 了解MVC和三层架构的设计模式
  4. 掌握企业开发的命名规范

什么是SpringWebMVC

Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就包含在Spring框架中。它的正式名称“Spring Web MVC”来自其源模块的名称(Spring-webmvc),但它通常被称为"SpringMVC".

什么是MVC

Model模型:是应⽤程序的主体部分,⽤来处理程序中数据逻辑的部分

View视图:指在应⽤程序中专⻔⽤来与浏览器进⾏交互,展⽰数据的资源

Controller控制器:可以理解为⼀个分发器,⽤来决定对于视图发来的请求,需要⽤哪⼀个模型来处理,以及处理完后需要跳回到哪⼀个视图。即⽤来连接视图和模型

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

MVC是一种思想,而Spring MVCMVC的一种实现


SpringMVC

SpringMVC项目的创建和上面创建SpringBoot项目一样.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

不过目前推崇的前后端分离已经不需要View层了,于是乎:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

学习Spring web mvc

  1. 建立连接
  2. 请求
  3. 响应
建立连接
@RequestMapping

类注解、方法注解

作用范围:

  1. 当一个类有多个注解的时候,这些注解没有先后顺序

    类路径+方法路径

    @RequestMapping("/user")// /可加可不加 但是我建议你加
    @RestController
    public class UserController {
     @RequestMapping("/hello")
     public String hello()
     {
         return "hello";
     }
    }
    
    

    此时访问路径:[127.0.0.1:8080/user/hello](http://127.0.0.1:8080/user/hello)

  2. 方法上

    @RestController
    public class UserController {
        @RequestMapping("/hello")
        public String hello()
        {
            return "hello";
        }
    }
    

请求方式是Get还是Post

  1. get通过浏览器访问的方式为get
  2. post

请求

指定请求方式
@RequestMapping("/user")
@RestController
public class UserController {
    @RequestMapping(value = "/hello",method = RequestMethod.GET)
    // 注解里,双引号的值会赋给"value"这个属性
    // 只有一个属性的时候,且属性名为value,可以省略
    public String hello()
    {
        return "hello";
    }
}
请求单个参数
@RequestMapping("/r1")
    public String r1(String name){
        return "接受到参数 name:" + name;
    }

    @RequestMapping("/r2")
    public String r2(int age){
        return "接受到参数 age:" + age;
    }
请求多个参数
@RequestMapping("/r3")
    public String r3(String name,Integer age){
        return "name:"+name+" "+"age:"+age;
        // 参数请求 顺序先后不分
    }
传递对象
// 创建userInfo
public class UserInfo {
    private Integer id;
    private String name;
    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

@RequestMapping("/r4")
    public String r4(UserInfo user){
        return user.toString();
    }
参数重命名

@RequestParam

@RequestMapping("/r5")
    public String r4(@RequestParam("name") String username, Integer age){
        return "username: " + username+ ", age: " + age;
    }

@RequestParam(“name”) 从请求中获取 name 的参数,并且赋值给 username 参数 且默认这个参数是必传的

设置参数为非必传的

我们先看一下RequestParam

public @interface RequestParam {
    @AliasFor("name")
    String value() default "";

    @AliasFor("value")
    String name() default "";

    boolean required() default true;

    String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
}

于是乎我们可以:将required设置为false

@RequestMapping("/r5")
    public String r5(@RequestParam(value = "name", required = false) String username, Integer age){
        return "username: " + username+ ", age: " + age;
    }
传递数组
@RequestMapping("/r7")
    public String r7(String[]arr){
        return Arrays.toString(arr);
    }
传递集合
@RequestMapping("/r8")
    public String r8(@RequestParam("list") List<String> list){
        return list.toString();
    }

在Spring MVC中,@RequestParam 注解用于从请求中提取参数值。@RequestParam("list") List<String> list 表示从请求中获取名为 “list” 的参数,并将其绑定到一个 List<String> 类型的变量 list 上。

这种方式常用于接收前端传递的多个相同类型的参数,例如,前端通过 URL 或者表单提交将多个字符串参数传递给后端。通过将它们绑定到一个 List<String> 类型的参数上,你可以轻松地处理多个相同类型的参数。

请求 URL 如下:

/r8?list=value1&list=value2&list=value3

通过上述的 @RequestParam("list") List<String> list,Spring 将自动将这些值绑定到一个列表中,你可以在方法体内使用这个 list 参数来访问传递的多个值。

总的来说,这是一种方便的方式,用于处理请求中包含多个相同类型参数的场景。

在Web开发中,有时候我们需要从前端接收一组相同类型的参数。使用 List<String> 类型的参数绑定可以方便地处理这种情况,而不需要为每个参数定义一个独立的变量。

考虑以下情景:

  1. 表单提交: 当用户通过表单提交多个相同类型的数据时,可以将这些数据绑定到一个 List<String> 中。例如,一个多选框(Checkbox)的多个选项。

  2. URL参数: 当通过URL传递多个相同类型的参数时,使用List<String> 可以更清晰地表达意图。例如,/r8?list=value1&list=value2&list=value3

  3. RESTful风格的请求: 在RESTful风格的API中,有时需要从请求体或路径中接收多个相同类型的数据。

绑定到 List<String> 的好处包括:

  • 代码简洁: 不需要为每个参数定义一个变量,通过一个 List 就可以容纳所有的值。

  • 可扩展性: 如果前端需要传递更多的相同类型的参数,代码不需要做太多修改。

  • 清晰明了: 通过命名为 list,表达了这是一组相同类型的数据。

传递JSON数据
JSON与Javascript的关系

没有关系, 只是语法相似, js开发者能更快的上⼿⽽已, 但是他的语法本⾝⽐较简单, 所以也很好学

JSON 优点
  1. 简单易⽤: 语法简单,易于理解和编写,可以快速地进⾏数据交换

  2. 跨平台⽀持: JSON可以被多种编程语⾔解析和⽣成, 可以在不同的平台和语⾔之间进⾏数据交换和传输

  3. 轻量级: 相较于XML格式, JSON数据格式更加轻量级, 传输数据时占⽤带宽较⼩, 可以提⾼数据传输速度

  4. 易于扩展: JSON的数据结构灵活,⽀持嵌套对象和数组等复杂的数据结构,便于扩展和使⽤

  5. 安全性: JSON数据格式是⼀种纯⽂本格式,不包含可执⾏代码, 不会执⾏恶意代码,因此具有较⾼的安全性

public class JSONUtils {
    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        UserInfo userInfo = new UserInfo();
        userInfo.setName("zhangsan");
        userInfo.setAge(18);
        userInfo.setId(12);

        // 对象转 JSON
        String s = objectMapper.writeValueAsString(userInfo);
        System.out.println(s);

        // JSON 转成 java 对象
        UserInfo userInfo1 = objectMapper.readValue(s,UserInfo.class);
        System.out.println(userInfo1);
    }
}

@RequestMapping("/r9")
    public String r9(@RequestBody UserInfo userInfo){
        return userInfo.toString();
    }

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

获取URL中的参数

@PathVariable

@RequestMapping("/r10/{articleId}")
    public String r10(@PathVariable Integer articleId){
        return "articleId:"+articleId;
    }

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

上传文件

@RequestPart

@RequestMapping("/r11")
    public String r11(@RequestPart MultipartFile file){
        return "获取上传文件:" + file.getOriginalFilename();
    }

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

@RequestMapping("/r11")
    public String r11(@RequestPart MultipartFile file) throws IOException {
        String fileName = file.getOriginalFilename();
        file.transferTo(new File("D:/temp/"+fileName));
        return "获取上传文件:" + file.getOriginalFilename();
    }

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这段代码虽然也可以不加注解,但是建议还是将注解加上去

获取Cookie/Session
Cookie

HTTP 协议⾃⾝是属于 “⽆状态” 协议.

无状态协议:

默认情况下 HTTP 协议的客⼾端和服务器之间的这次通信, 和下次通信之间没有直接的联系.

但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的.

例如登陆⽹站成功后, 第⼆次访问的时候服务器就能知道该请求是否是已经登陆过了.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Session

会话:对话的意思

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在计算机领域, 会话是⼀个客⼾与服务器之间的不中断的请求响应. 对客⼾的每个请求,服务器能够识

别出请求来⾃于同⼀个客⼾. 当⼀个未知的客⼾向Web应⽤程序发送第⼀个请求时就开始了⼀个会话.

当客⼾明确结束会话或服务器在⼀个时限内没有接受到客⼾的任何请求时,会话就结束了.

⽐如我们打客服电话

每次打客服电话, 是⼀个会话. 挂断电话, 会话就结束了

下次再打客服电话, ⼜是⼀个新的会话.

如果我们⻓时间不说话, 没有新的请求, 会话也会结束

服务器同⼀时刻收到的请求是很多的. 服务器需要清楚的区分每个请求是从属于哪个⽤⼾, 也就是属于哪个会话, 就需要在服务器这边记录每个会话以及与⽤⼾的信息的对应关系.

Session是服务器为了保存⽤⼾信息⽽创建的⼀个特殊的对象.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Session的本质就是⼀个 “哈希表”, 存储了⼀些键值对结构. Key 就是SessionID, Value 就是⽤⼾信息(⽤⼾信息可以根据需求灵活设计).

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

SessionIsd是由服务器生成的一个"唯一性字符串",从Session机制的角度来看,这个唯一性字符串称为"Sessionld".但是站在整个登录流程中看待,也可以把这个唯一性字符串称为"token".
上述例子中的令牌ID,就可以看做是Sessionld,只不过令牌除了ID之外,还会带一些其他信息,比如时间,签名等.

  1. 当⽤⼾登陆的时候, 服务器在 Session 中新增⼀个新记录, 并把 sessionId返回给客⼾端. (通过HTTP 响应中的 Set-Cookie 字段返回).

  2. 客⼾端后续再给服务器发送请求的时候, 需要在请求中带上 sessionId. (通过 HTTP 请求中的Cookie 字段带上).

  3. 服务器收到请求之后, 根据请求中的 sessionId在 Session 信息中获取到对应的⽤⼾信息, 再进⾏后续操作.找不到则重新创建Session, 并把SessionID返回

Session默认是保存在内存中的.如果重启服务器则Session数据就会丢失.

Cookie和Session的区别

在此之前我们可以举一个例子

学生入学

学校收集学生信息,姓名,班级,身份证号等等

那么学校该如何存储呢?

NumberNameAgeAttribute
1张三18CS
2李四17CS
3王五20CS

学校存储信息之后,给学生发学生证

学生出入学校,使用学生证(就好比是Cookie)来证明身份

但是,学生证可以造假,但是学校的教务系统的信息是造假不了的

于是乎:Cookie是可以造假的,但是Session不行

  1. 用户提供账号和密码,服务器进行验证。

  2. 服务器验证通过,会把信息存储在Session中,把SessionId返回给客户端(通过Set-Cookie的方式)

  3. 客户端收到响应,把sessionID存储在Cookie

  4. 后续的请求中,客户端带着SessionID去请求(带着Cookie信息去请求)

    request.getSession就是从Cookie中获取SessionID,并且根据SessionID获取Session信息

区别如下:

  • Cookie是客户端保存用户信息的一种机制.Session是服务器端保存用户信息的一种机制:
  • CookieSession之间主要是通过Sessionld关联起来的,SessionldCookieSession之间的桥梁
  • CookieSession经常会在一起配合使用.但是不是必须配合.
    • 完全可以用Cookie来保存一些数据在客户端.这些数据不一定是用户身份信息,也不一定是Sessionld
    • Session中的sessionld也不需要非得通过Cookie/Set-Cookie传递,比如通过URL传递

共同点:都是会话机制

Cookie是客户端机制

Session是服务器机制

Cookie存储的信息由程序员而定

Session也不一定必须存在Cookie

传统方式获取Cookie
@RestController
@RequestMapping("/request")
public class RequestController {
    @RequestMapping("/getCookie")
    public String getCookie(HttpServletRequest request) // 内置对象,有需要就加上,没需要就不加 需要几个就加几个
    {
        Cookie[] cookies = request.getCookies();

//        Arrays.stream(cookies).forEach(x->{
//            System.out.println(x.getName()+":"+x.getValue());
//        });

        // 等价于
        if (cookies != null){
        for(Cookie c:cookies){
            System.out.println(c.getName()+":"+c.getValue());
        }
        return "获取Cookies成功";
        }
        else
            return "获取Cookies不成功";
    }
}
SpringBoot获取Cookie
@RequestMapping("/getCookie2")
    public String getCookie2(@CookieValue ("riyewuxiushi")String riyewuxiushi){
        return "riyewuxiushi"+riyewuxiushi;
    }
传统方式获取Session
	@RequestMapping("/setSession")
    public String setSession(HttpServletRequest request){
        HttpSession session = request.getSession(); // 默认值为 true
        session.setAttribute("userName","zhangsan");
        return "设置session成功";
    }

    @RequestMapping("/getSession")
    public String getSession(HttpServletRequest request){
        HttpSession session = request.getSession();
        String userName = (String) session.getAttribute("userName");
        return "登录用户:"+ userName;
    }
SpringBoot获取Session
@RequestMapping("/getSession2")
    public String getSession2(HttpSession session){ // 内置对象
        String userName = (String) session.getAttribute("userName");
        return "登录用户:"+ userName;
    }
	@RequestMapping("/getSession3")
    public String getSession3(@SessionAttribute(value = "userName",required = false) String userName){
        return "登录用户:"+ userName;
    }
获取Header
传统获取Header
	@RequestMapping("/getheader")
    public String getheader(HttpServletRequest request){
        String userAgent = request.getHeader("User-Agent");
        return "userAgent"+userAgent;
    }
springboot方式获取Header
	@RequestMapping("/getheader2")
    public String getheader2(@RequestHeader("User-Agent")String userAgent){
        return "userAgent"+userAgent;
    }

响应

返回静态页面
@RequestMapping("/return")
//@RestController
@Controller
// 多个注解的时候 注解不分先后顺序
public class ReturnController {
    @RequestMapping("/r1")
    public String r1(){
        return "/index.html";
    }
}
@RestContraller@Controller的区别

@RestController@Controller 是 Spring Framework 中用于标记类的注解,用于定义处理 HTTP 请求的控制器。它们之间有一些区别和联系。

区别:

  1. 返回值处理:@Controller 通常用于创建传统的基于视图的 Web 应用程序,它的方法可以返回模型数据和视图名称,最终由视图解析器解析为具体的视图。而 @RestController 则是用于创建 RESTful Web 服务的控制器,它的方法返回的是数据对象,会自动通过消息转换器将数据转为 JSON/XML 等格式,不会经过视图解析器。
  2. 默认行为:@RestController 组合了 @Controller@ResponseBody 注解的功能。@ResponseBody 注解表示方法的返回值将直接写入 HTTP 响应体中,而不是通过视图解析器解析为视图。因此,@RestController 类的每个方法都默认返回数据对象,而不是视图。
  3. 使用场景:@Controller 适用于传统的基于视图的 Web 应用程序,例如使用 Thymeleaf、JSP 或者其他模板引擎渲染视图。@RestController 适用于构建 RESTful Web 服务,响应 JSON 或 XML 格式的数据。

联系:

  1. 标记作用:@RestController@Controller 都是用于标记类的注解,将类声明为 Spring Framework 的组件,用于处理 HTTP 请求。
  2. 注解继承:@RestController@Controller 注解的特殊化,可以认为是 @Controller 的增强版本。@RestController 继承了 @Controller 的所有功能,同时还提供了自动将方法返回值转换为数据格式的能力。
// @RestController 源码
@Target({ElementType.TYPE}) // 表示注解的范围
@Retention(RetentionPolicy.RUNTIME) // 注解的生命周期
@Documented // 
// 上面三个是元注解:是可以注解到 其他注解 的注解
@Controller // ----> 这说明 RestContraller 是基于 Controller 实现的
@ResponseBody
public @interface RestController {
    @AliasFor(
        annotation = Controller.class
    )
    String value() default "";
}

@RestController = @Controller + @ResponseBody

@Controller : 告诉Spring帮我们管理那些程序

@ResponseBody:返回数据

路径问题
  • servlet路径有项目名,是因为一个tomcat下面可以部署多个项目,我们需要通过路径来进行区分
  • spring路径不需要有项目名,是因为springboot内置了tomcat,一个tomcat下面就部署当前这一个项目
  • 如果部署多个项目,就启动多个tomcat
一个项目部署多个服务

IDEA 2023.2新版如何将同一个项目开启多个

返回数据@ResponseBody
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
}

即可以修饰类,又可以修饰方法

修饰类:表示该类所有的方法 返回的是数据

修饰方法:表示该方法返回的是数据

	@RequestMapping("/r1")
    public String r1(){
        return "/index.html";
    }

    @ResponseBody
    @RequestMapping("/r2")
    public String r2(){
        return "hello spring";
    }
返回HTML片段
	@ResponseBody
    @RequestMapping("/r3")
    public String r3(){
        return "<h1>我是返回的片段</h1>";
    }
  • get可以被缓存 幂等
  • post不可以被缓存
返回JSON
	@ResponseBody
    @RequestMapping("/r4")
    public UserInfo r4(){
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName("zhangsan");
        userInfo.setAge(19);
        return userInfo;
    }
	@ResponseBody
    @RequestMapping("/r5")
    public Map<String ,String> r5(){
        HashMap map = new HashMap();
        map.put("k1","v1");
        map.put("k2","v2");
        return map;
    }

    //@ResponseBody
    @RequestMapping("/r6")
    public String r6(){
        return "/a.js";
    }

    @RequestMapping("/r7")
    public String r7(){
        return "/b.css";
    }
设置状态码
	@ResponseBody
    @RequestMapping("/r8")
    public String r8(HttpServletResponse response){
        response.setStatus(401);
        return "设置状态码成功";
    }

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

状态码的设置不影响页面的显示

设置Header
设置Content-Type

我们通过设置 produces属性的值, 设置响应的报头Content-Type

// @RequestMapping源码

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    String name() default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
}
  1. value: 指定映射的URL

  2. method: 指定请求的method类型, 如GET, POST

  3. consumes: 指定处理请求(request)的提交内容类型(Content-Type),例如application/json,text/html;

  4. produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回

  5. Params: 指定request中必须包含某些参数值时,才让该⽅法处理

  6. headers: 指定request中必须包含某些指定的header值,才能让该⽅法处理请求

 	@ResponseBody
    @RequestMapping("/r9")
    public String r9(){
        return "123333";
    }

	@ResponseBody
    @RequestMapping(value = "/r9",produces = "application/json")
    public String r9(){
        return "123333";
    }
设置其他Header

设置其他Header的话, 需要使⽤Spring MVC的内置对象HttpServletResponse 提供的⽅法来进⾏设置

	@ResponseBody
    @RequestMapping(value = "/r10",produces = "application/json")
    public String r10(HttpServletResponse response){
        response.setHeader("myHeader","myHeaderValue");
        return "设置Header成功";
    }

void setHeader(String name, String value) 设置⼀个带有给定的名称和值的 header. 如果 name已经存在, 则覆盖旧的值

案例

学习建议:

最开始学习的时候:小步慢跑

每次写少量的代码,就进行测试

不要一次把代码全部写完,一次性进行测试

随着对代码的熟悉,可以逐渐加大步伐

加法计算器

前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
     <form action="calc/sum" method="post">
        <h1>计算器</h1>
        数字1:<input name="num1" type="text"><br>
        数字2:<input name="num2" type="text"><br>
        <input type="submit" value=" 点击相加 ">
    </form>
</body>

</html>

后端接到需求的时候

  1. 需求评审
  2. 开发
    1. 接口的定义
    2. 开发
    3. 测试(自行测试,与测试人员无关)
  3. 联调(后端和前端联调)
  4. 提测(测试人员的工作)
  5. 上线
  6. 维护
  7. 下线

后端代码

接口定义

两个原则

  1. 看我需要什么(请求参数)
  2. 看对方需要什么(响应结果)

请求参数:参与计算的两个数字

响应结果:计算结果

/calc/sum

参数:num1 , num2

返回结果:两者计算的数据


请求路径:calc/sum

请求⽅式:GET/POST

接⼝描述:计算两个整数相加

请求参数:

参数名类型是否必须备注
num1Integer参与计算的第一个数
num2Integer参与计算的第二个数

响应数据:

Content-Type : text/html

@RestController
@RequestMapping("/calc")
public class CalcController {
    @RequestMapping("/sum")
    public String sum(Integer num1, Integer num2){
        Integer sum  = num1 + num2;
        return "<h1>计算机计算结果: "+sum+"</h1>";
    }
}

问题可能出现的地方:

  1. 前端
  2. 后端
  3. 前后端交互
    1. 请求有没有发出去
    2. 后端有没有收到请求

用户登录

前端代码

// login.html
<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <title>登录页面</title>
    </head>

    <body>
        <h1>用户登录</h1>
        用户名:<input name="userName" type="text" id="userName"><br>
        密码:<input name="password" type="password" id="password"><br>
        <input type="button" value="登录" onclick="login()">

        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
        <script>
            function login() {
               $.ajax({
                   type:"post",
                   url:"/login/check",
                   data:{
                       userName:$("#userName").val(),
                       password:$("#password").val()
                   },
                   success:function(result){
                       if (result == true){
                           // 用户名和密码正确
                           location.href = "/index.html";
                           // location.assign("index.html");
                           // location.replace("index.html");
                       }else{
                           alert("用户名或密码错误");
                       }
                   }
               });

            }

        </script>
    </body>

</html>
// index.html
<!doctype html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>用户登录首页</title>
    </head>

    <body>
        登录人: <span id="loginUser"></span>

        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
        <script>
            $.ajax({
                url:"/login/index",
                type:"get",
                success:function (result) {
                    $("#loginUser").text(result);
                }
            });
        </script>
    </body>

</html>

后端代码

用户验证:

/login/check

参数:

userName

password

响应:

用户和密码是否正确

true

false


获取登录的用户

/login/index

参数:

响应:

登录的用户

@RequestMapping("/login")
@RestController
public class LoginController {
    @RequestMapping("/check")
    public boolean check(String userName, String password, HttpSession session){
        // 校验账号和密码是否为空
//        if (userName == null || "".equals(userName) || password == null || "".equals(password)){
//            return false;
//        }
        if (!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)){
            return false;
        }
        // 校验账号和密码是否正确
        // 模拟数据
        if("zhangsan".equals(userName) && "123456".equals(password)){ // 防止空指针,养成习惯 常量写在前面
            session.setAttribute("userName",userName);
            return true;
        }
        return false;
    }

    @RequestMapping("/index")
    public String index(HttpSession session){
        String userName = (String) session.getAttribute("userName");
        return userName;
    }
}

留言板

前端代码

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>留言板</title>
        <style>
            .container {
                width: 350px;
                height: 300px;
                margin: 0 auto;
                /* border: 1px black solid; */
                text-align: center;
            }

            .grey {
                color: grey;
            }

            .container .row {
                width: 350px;
                height: 40px;

                display: flex;
                justify-content: space-between;
                align-items: center;
            }

            .container .row input {
                width: 260px;
                height: 30px;
            }

            #submit {
                width: 350px;
                height: 40px;
                background-color: orange;
                color: white;
                border: none;
                margin: 10px;
                border-radius: 5px;
                font-size: 20px;
            }
        </style>
    </head>

    <body>
        <div class="container">
            <h1>留言板</h1>
            <p class="grey">输入后点击提交, 会将信息显示下方空白处</p>
            <div class="row">
                <span>谁:</span> <input type="text" name="" id="from">
            </div>
            <div class="row">
                <span>对谁:</span> <input type="text" name="" id="to">
            </div>
            <div class="row">
                <span>说什么:</span> <input type="text" name="" id="say">
            </div>
            <input type="button" value="提交" id="submit" onclick="submit()">
            <!-- <div>A 对 B 说: hello</div> -->
        </div>

        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
        <script>
            // 页面加载时,显示留言信息
            // 从后端获取留言信息,显示在页面上
            $.ajax({
                type:"get",
                url:"/message/getList",
                success:function (messages) {
                    for (var message of messages){
                        var html = "<div>"+message.from+"对"+message.to+"说:"+message.message+"</div>";
                        $(".container").append(html);
                    }
                }
            });
            function submit(){
                //1. 获取留言的内容
                var from = $('#from').val();
                var to = $('#to').val();
                var say = $('#say').val();
                if (from== '' || to == '' || say == '') {
                    return;
                }
                $.ajax({
                    type:"post",
                    url:"/message/publish",
                    data:{
                        from:from,
                        to:to,
                        message:say
                    },
                    success:function (result) {
                        if (result == true){
                            // 添加成功
                            //2. 构造节点
                            var divE = "<div>"+from +"对" + to + "说:" + say+"</div>";
                            //3. 把节点添加到页面上
                            $(".container").append(divE);
                            //4. 清空输入框的值
                            $('#from').val("");
                            $('#to').val("");
                            $('#say').val("");
                        }else{
                            alert("发表失败");
                        }
                    }
                });

            }

        </script>
    </body>

</html>

后端代码

  1. 提交留言:用户输入留言信息的时候,后端需要将留言信息保存起来

    URL:/message/publish

    参数

    • from:发表人
    • to:接收人
    • message:信息

    返回:提交成功/失败

    true、false

  2. 展示留言:页面展示的时候,需要从后端获取到所有的留言信息

    URL:/message/getList

    参数

    返回:全部的留言信息

    List<MessageInfo>

lombok工具包介绍
  1. 新项目

    创建项目的时候直接加入依赖

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  2. 老项目

    在poe.xml中引入依赖,去maven中央仓库找

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.24</version>
                <scope>provided</scope>
            </dependency>
    
@Data
public class MessageInfo {
 private String from;
 private String to;
 private String message;
 }

@Data 会自动生成 get、set方法

idea会自己进行反编译

单独使用可以@Getter @Setter

注解作用
@Getter自动添加getter方法
@Setter自动添加setter方法
@ToString自动添加toString方法
@EqualsAndHashCode⾃动添加 equals 和 hashCode ⽅法
@NoArgsConstructor自动添加无参构造方法
@AllArgsConstructor自动添加全属性构造方法,顺序按照属性的定义顺序
@NonNull属性不能为null
@RequiredArgsConstructor自动添加必需属性的构造方法,final+@NonNull的属性为必需

@Data = @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor

+ @NoArgsConstructor

  1. 更快地引入依赖

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    下载这个就好啦~然后重启IDEA

    使用方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

package org.example.springmvc_demo;

import lombok.Data;

/**
 * @author 日夜无休时
 * @date 2024/1/29
 */
@Data
public class MessageInfo {
    
    private String from;
    private String to;
    private String message;

    // 换一个新工具 lombook @Data
//    public String getFrom() {
//        return from;
//    }
//
//    public void setFrom(String from) {
//        this.from = from;
//    }
//
//    public String getTo() {
//        return to;
//    }
//
//    public void setTo(String to) {
//        this.to = to;
//    }
//
//    public String getMessage() {
//        return message;
//    }
//
//    public void setMessage(String message) {
//        this.message = message;
//    }

}

package org.example.springmvc_demo;

import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 日夜无休时
 * @date 2024/1/29
 */
@RestController
@RequestMapping("/message")
public class MessageController {
    private  List<MessageInfo>messageInfos = new ArrayList<>();

    @RequestMapping("/publish")
    public boolean publishMessage(MessageInfo messageInfo){
        if (!StringUtils.hasLength(messageInfo.getFrom())
                || !StringUtils.hasLength(messageInfo.getTo())
                || !StringUtils.hasLength((messageInfo.getMessage()))){
            return false;
        }
        // 暂时存放在内存中
        messageInfos.add(messageInfo);
        return true;
    }

    @RequestMapping("/getList")
    public List<MessageInfo> getList(){
        for (MessageInfo messageInfo : messageInfos){

        }

        return messageInfos;
    }
}

图书管理系统

定义接口

接口定义:

  • 服务提供方:

    1. 提供什么服务

    2. 提供服务时,需要什么参数

    3. 处理之后,需要给对方什么响应

  • 客户端角度:

    1. 我需要什么服务
    2. 服务端的参数 我是否有
    3. 对方给我提供的信息,能否满足我的需求
  1. 登录

    URL: /user/login

    参数:用户名和密码

    userName

    password

    返回:

    true:用户名和密码正确

    false:用户名和密码错误

  2. 图书列表

    URL:/book/getList

    参数:无

    返回:图书列表

    List

MOCK

虚拟的、假的。开发的时候通常是几个团队并行开发,开发后需要进行测试(自测),如果测试时,依赖方还没完成开发,调用方就采用mock的方式,先进行测试。

应用分层

一种开发规范

三层架构(软件设计架构方式)

  1. 表现层:就是展示数据结果和接受用户指令的,是最靠近用户的一层
  2. 业务逻辑层:负责处理业务逻辑,里面有复杂业务的具体实现
  3. 数据层:负责存储和管理与应用程序相关的数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

命名规范
  1. 类名 大驼峰
  2. 变量名 小驼峰
MVC和三层架构之间的关系

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

共同点

  • 解耦(高内聚,低耦合)

    模块内 关系尽量紧密(高内聚)

    模块间 关系尽量关联低(低耦合)

    比如说:公司与公司之间,关联应该越小越好,公司内部,员工应该团结

SpringMVC小结

什么是springmvc

spring web mvc

@RequestMapping

既是类注解,也是方法注解

访问的URL路径 = 类路径 + 方法路径

默认支持 get/post,可以使用method属性来限制请求方式

请求

  1. 请求当个参数
  2. 请求多个参数
  3. 请求参数为对象
  4. 对参数重命名 @RequestParam 默认是必传参数,设置 required = false 就是非必传
  5. 设置参数为非必传
  6. 请求参数为JSON @RequestBody
  7. Cookie & Session
  8. 传递数组
  9. 传递集合@RequestParam
  10. 获取Header

响应

  1. 返回静态页面
  2. 返回数据@ResponseBody
  3. 返回HTML片段
  4. 返回JSON
  5. 设置响应头(状态码、编码、其他header

注解总结

  1. @RequestMapping: 路由映射
  2. @RequestParam: 后端参数重命名
  3. @RequestBody: 接收JSON类型的参数
  4. @PathVariable: 接收路径参数
  5. @RequestPart: 上传⽂件
  6. @ResponseBody: 返回数据
  7. @CookieValue: 从Cookie中获取值
  8. @SessionAttribute: 从Session中获取值
  9. @RequestHeader: 从Header中获取值
  10. @Controller: 定义⼀个控制器, Spring 框架启动时加载, 把这个对象交给Spring管理. 默认返回视图.
  11. @RestController: @ResponseBody + @Controller 返回数据

Cookie和Session

Cookie 和Session都是会话机制, Cookie是客⼾端机制, Session是服务端机制. ⼆者通过SessionId来关联. Spring MVC内置HttpServletRequest, HttpServletResponse两个对象. 需要使⽤时, 直接在⽅法中添加对应参数即可, Cookie和Session可以从HttpServletRequest中来获取, 也可以直接使⽤HttpServletResponse设置Http响应状态码.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1451778.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Sora:AI视频生产力的颠覆性跃进,让创意瞬间成“视界”!

在AI视频技术宇宙中&#xff0c;RunwayGen2、Stable Video Diffusion和Pika等明星产品早已名声在外。然而&#xff0c;今日横空出世的Sora犹如一颗璀璨新星&#xff0c;以其震撼性的创新突破&#xff0c;在视频制作领域掀起了一场革命&#xff01;相较于市面上同类AI视频神器&a…

【Java程序员面试专栏 分布式中间件】Redis 核心面试指引

关于Redis部分的核心知识进行一网打尽,包括Redis的基本概念,基本架构,工作流程,存储机制等,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 基础概念 明确redis的特性、应用场景和数据结构 什么是Redis,Redis有哪些应用场景 Redi…

互联网加竞赛 基于计算机视觉的身份证识别系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器视觉的身份证识别系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-sen…

Sora:继ChatGPT之后,OpenAI的又一力作

关于Sora的报道&#xff0c;相信很多圈内朋友都已经看到了来自各大媒体铺天盖地的宣传了&#xff0c;这次&#xff0c;对于Sora的宣传&#xff0c;绝不比当初ChatGPT的宣传弱。自OpenAI发布了GPT4之后&#xff0c;就已经有很多视频生成模型了&#xff0c;不过这些模型要么生成的…

【JavaEE】_CSS选择器

目录 1. 基本语法格式 2. 引入方式 2.1 内部样式 2.2 内联样式 2.3 外部样式 3. 基础选择器 3.1 标签选择器 3.2 类选择器 3.3 ID选择器 4. 复合选择器 4.1 后代选择器 4.2 子选择器 4.3 并集选择器 4.4 伪类选择器 1. 基本语法格式 选择器若干属性声明 2. 引入…

C语言从零实现贪吃蛇小游戏

制作不易&#xff0c;点赞关注一下呗&#xff01;&#xff01;&#xff01; 文章目录 前言一. 技术要点二、WIN32API介绍三、贪吃蛇游戏设计与分析 1.游戏开始前的初始化 2.游戏运行的逻辑 总结 前言 当我们掌握链表这样的数据结构之后&#xff0c;我们就可以用它来…

Rust 学习笔记 - Hello world

前言 本文将讲解如何完成一个 Rust 项目的开发流程&#xff0c;从编写 “Hello, World!” 开始&#xff0c;到使用 Cargo 管理和运行项目。 编写 Hello world 开始一个新项目很简单&#xff0c;首先&#xff0c;创建一个包含 main.rs 文件的 hello_world 文件夹&#xff0c;…

GPT翻译网站的加载与使用

Sider: ChatGPT侧边栏 GPTs, GPT-4 Turbo, 联网, 绘图 sider.ai https://chromewebstore.google.com/detail/sider-chatgpt%E4%BE%A7%E8%BE%B9%E6%A0%8F-gpts-g/difoiogjjojoaoomphldepapgpbgkhkb?hlzh-CN 加入与移除 第二个翻译网站 https://chromewebstore.google.com/…

电商小程序08调用缓存

目录 1 将信息存入缓存中2 获取登录信息3 退出登录4 发布预览总结 小程序的登录功能里&#xff0c;如果只是将登录信息保存到全局变量中&#xff0c;存在的问题是如果小程序重新打开&#xff0c;用户的登录状态就丢失了。为了解决这个问题&#xff0c;我们需要用到微搭的缓存的…

13-k8s的控制器资源-rc控制器replicationcontrollers

一、rc控制器资源的概述 replicationcontrollers控制器资源&#xff0c;简称&#xff1a;rc控制器&#xff1b; 简单理解&#xff0c;rc控制器就是控制相同的pod副本数量&#xff1b; 使用rc控制器资源创建pod&#xff0c;就可以设定创建pod的数量&#xff1b; 二、rc控制器资源…

C++中对象的构造与析构顺序

一、对象的构造顺序 对象的构造&#xff0c;先被创建的对象&#xff0c;先被构造&#xff0c;先调用其构造函数 class A { private:int _a 0; public://构造函数A(int a 0){_a a;cout << "A(int a 0)" << " " << _a << endl…

NVIDIA 刚刚揭秘了他们的最新大作——Eos,一台跻身全球十强的超级计算机

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

HCIA-HarmonyOS设备开发认证V2.0-内核扩展组件

目录 一、CPU 占用率1.1、CPU 占用率基本概念1.2、CPU 占用率运行机制1.3、CPU 占用率开发流程 二、动态加载2.1、 动态加载基本概念2.2、动态加载运行机制 坚持就有收获 一、CPU 占用率 1.1、CPU 占用率基本概念 CPU&#xff08;中央处理器&#xff0c;Central Processing U…

Java 学习和实践笔记(11)

三大神器&#xff1a; 官方网址: http://www.jetbrains.com/idea/ 官方网址: https://code.visualstudio.com/ 官方网址: http://www.eclipse.org 装好了idea社区版&#xff0c;并试运行以下代码&#xff0c;OK&#xff01; //TIP To <b>Run</b> code, press &l…

洛谷AT_abc034_a[ABC034A] テスト

#先看题目 题目描述 输入格式 无 输出格式 无 题意翻译 输入两个数字 x 和 y&#xff0c;如果 y>x 输出Better&#xff0c;否则输出Worse。 输入输出样例 无 题目链接https://www.luogu.com.cn/problem/AT_abc034_a #思路 没有 #最后附上完整代码 #include&l…

(02)Hive SQL编译成MapReduce任务的过程

目录 一、架构及组件介绍 1.1 Hive底层架构 1.2 Hive组件 1.3 Hive与Hadoop交互过程 二、Hive SQL 编译成MR任务的流程 2.1 HQL转换为MR源码整体流程介绍 2.2 程序入口—CliDriver 2.3 HQL编译成MR任务的详细过程—Driver 2.3.1 将HQL语句转换成AST抽象语法树 词法、语…

二叉树的锯齿形层序遍历

1.题目 这道题是2024-2-16的签到题&#xff0c;题目难度为中等。 考察知识点为BFS算法和双端队列。 题目链接&#xff1a;二叉树的锯齿形层序遍历 给你二叉树的根节点 root &#xff0c;返回其节点值的 锯齿形层序遍历 。&#xff08;即先从左往右&#xff0c;再从右往左进行…

VScode写LaTeX配置,实测有效

环境配置请看LaTeX环境配置-TexLive&#xff0c;实测有效http://t.csdnimg.cn/0txlL VScode写LaTeX配置 0.smatra pdf下载 如果使用外部pdf查看器&#xff0c;比如我用的sumatra pdf,官网是Sumatra PDF reader download page 下载对应版本&#xff0c;比如64位&#xff0c;下…

【STM32 CubeMX】I2C中断方式与DMA方式

文章目录 前言一、I2C中断方式1.1 CubeMX配置I2C中断1.2 I2C中断函数使用Master模式Mem模式 1.3 DMA方式发送和接收CubeMX配置IIC DMA方式Master模式Mem模式 总结 前言 在STM32 CubeMX环境中&#xff0c;I2C&#xff08;Inter-Integrated Circuit&#xff09;通信协议的实现可…

机器人专题:我国机器人产业园区发展现状、问题、经验及建议

今天分享的是机器人系列深度研究报告&#xff1a;《机器人专题&#xff1a;我国机器人产业园区发展现状、问题、经验及建议》。 &#xff08;报告出品方&#xff1a;赛迪研究院&#xff09; 报告共计&#xff1a;26页 机器人作为推动工业化发展和数字中国建设的重要工具&…