SpringBoot SpringMVC (详解)

6. SpringBoot

Spring 的诞⽣是为了简化 Java 程序的开发的,⽽ Spring Boot 是为了快速开发 Spring 程序开发而诞生的。

Spring Boot 的优点:

  • 快速集成框架,Spring Boot 提供了启动添加依赖的功能,⽤于秒级集成各种框架。
  • 内置运⾏容器,⽆需配置 Tomcat 等 Web 容器,直接运⾏和部署程序
  • 快速部署项⽬,⽆需外部容器即可启动并运⾏项⽬。
  • 可以完全抛弃繁琐的 XML,使⽤注解和配置的⽅式进⾏开发。
  • ⽀持更多的监控的指标,可以更好的了解项⽬的运⾏情况。

6.1 SpringBoot 创建和使用演示

6.1.1 创建

  1. 安装Spirng Boot Helper插件,安装好之后它的名字就变成Spirng Initialzr and Assistant 了
    在这里插入图片描述在这里插入图片描述
  2. 创建 Spring Boot 项目

首先把 Maven 配置为国内源:
第⼀次打开 Spring Boot 项⽬需要加载很久,因为当前 Spring Boot 框架并没有在⾃⼰的本地仓库,为了加速 Spring Boot 项⽬的下载,在打开项⽬之前,先把 Maven 配置为国内源。
<1> 打开 settings
在这里插入图片描述
<2> 在这里插入图片描述
在这里插入图片描述
检查 User Settings file 的 settings.xml ⽂件是否存在,如果不存在,复制下⾯配置了国内源的 settings.xml ⽂件,放到 User Settings file ⽬录下。

// 配置了国内源的 settings.xml
<settings xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="htt p://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven. apache.org/xsd/settings-1.1.0.xsd"> 
<localRepository>C:\Users\intel\.m2\repository</localRepository> <mirrors><mirror><id>alimaven</id><name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf></mirror></mirrors>
</settings>

如果存在,检查 settings.xml 是否配置了国内源,对照代码修改配置即可。
<3>删除本地存储 jar ⽬录中的所有⽂件
在这里插入图片描述
<4> 切换到 Idea 中,重新下载 jar 包:
在这里插入图片描述
如果出现中⽂会导致下载了 jar 包,但是在项⽬中不能正常使⽤;如果还是下载失败那就是本地⽹速问题,尝试更好⽹络,使⽤⼿机热点或朋友的⼿机热点尝试,如果还是不⾏,间隔 4 ⼩时之后再试。

正式开始创建项⽬:
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述点击 Finish 就完成 Spring Boot 的项⽬创建了。

网页版创建:
不使⽤ Idea 也可以创建 Spring Boot 项⽬,我们可以使⽤ Spring 官⽅提供的⽹⻚版来创建Spring Boot 项⽬。
<1> 先访问:https://start.spring.io在这里插入图片描述在这里插入图片描述
点击⽣成按钮会下载⼀个 Spring Boot 的 zip 包,解压 zip 之后⽬录如下:
在这里插入图片描述
<2> 使⽤ Idea 打开之后,Spring Boot 项⽬就算创建成功了
在这里插入图片描述

6.1.1 使用

Spring项目的特点:约定大于配置。

  • 约定把要注入到容器的类和启动类放到同级目录下,此时Spring Boot 项目才能将bean注入到容器中,类上标注 @SpringBootApplication 就可以启动 Spring Boot 项⽬了。
    在这里插入图片描述
    对⽐ Spring 的项⽬我们也可以看到这⼀特点,⽐如在 Spring 中也是要配置 Bean 的扫描路径的,⽽ Spring Boot 则不需要,Spring 配置如下:在这里插入图片描述

项目目录介绍

  • src/main/java 为 Java 源代码
  • src/main/resources 为静态资源或配置⽂件,/static:静态资源⽂件夹;/templates:模版资源⽂件夹。在这里插入图片描述
  1. 运行项目
    点击启动类的 main ⽅法就可以运⾏ Spring Boot 项⽬了,
    在这里插入图片描述
    启动成功如下图所示:
    在这里插入图片描述

  2. 输出 Hello world
    之前 Spring 是⼀个普通 Java 项⽬,没 办法直接和浏览器进⾏互动,⽤ Spring Boot 可以直接实现和浏览器及⽤户的交互。
    <1> 在创建的项⽬包路径下创建 UserController ⽂件,实现代码如下:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;@RestController 
@RequestMapping("/user") 
public class UserController {@RequestMapping("/sayhi") public String sayHi(){ return  "Hi,Spring Boot."; }
}

<2> 重新启动项⽬,访问 http://localhost:8080/user/sayhi 最终效果如下:
在这里插入图片描述

6.2 SpringBoot 热部署

  1. 添加热部署框架⽀持
    在 pom.xml 中添加如下框架引⽤:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope>
</dependency>
  1. Settings 开启项⽬⾃动编译
    在这里插入图片描述在这里插入图片描述

  2. 开启运⾏中热部署
    在这里插入图片描述
    在这里插入图片描述

⾼版本 Idea 设置(IntelliJ IDEA 2021.2 之后版本)在这里插入图片描述

  1. 使⽤ Debug 启动(⾮Run)

**在这里插入图片描述**

6.3 SpringBoot 配置文件

6.3.1 配置文件作用

整个项⽬中所有重要的数据都是在配置⽂件中配置的:

  • 数据库的连接信息(包含⽤户名和密码的设置),
  • 项⽬的启动端⼝
  • 第三⽅系统的调⽤秘钥等信息
  • ⽤于发现和定位问题的普通⽇志和异常⽇志等

如果没有配置信息,那么 Spring Boot 项⽬就不能连接和操作数据库,甚⾄是不能保存可以⽤ 于排查问题的关键⽇志,所以配置⽂件⾮常重要。

6.3.2 配置⽂件的格式

在这里插入图片描述

  • 理论上讲 properties 可以和 yml ⼀起存在于⼀个项⽬当中,当 properties 和 yml ⼀起存在⼀个项⽬中时,如果配置⽂件中出现了同样的配置,⽐如 properties 和 yml 中都配置“server.port”, 那么这个时候会以 properties 中的配置为主,也就是 .properties 配置⽂件的优先级最⾼,但加载 完 .properties ⽂件之后,也会加载 .yml ⽂件的配置信息。实际的业务当中,我们通常会采取⼀种统⼀的配置⽂件格式,这样可以更好的维护(降低故障率)。
6.3.2.1 .properties 详解

properties 配置⽂件是最早期的配置⽂件格式,也是创建 Spring Boot 项⽬默认的配置⽂件。

  1. 语法:
    properties 是以键值的形式配置的,key 和 value 之间是以“=”连接。
# 配置项⽬端⼝号
# 配置⽂件中使⽤“#”来添加注释信息。
server.port=8084 
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding= utf8
spring.datasource.username=root
spring.datasource.password=root

从上述配置key看出,properties 配置⽂件中会有很多的冗余的信息:在这里插入图片描述

  1. 读取配置⽂件

主动的读取配置⽂件中的内容,可以使⽤ @Value 注解来实现,@Value 注解使⽤“${}”的格式读取。

@Component 在 Spring Boot 启动时候会注⼊到框架中,注⼊到框架中时会执⾏ @PostConstruct初始化⽅法,这个时候就能读取到配置信息了。

示例:

import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;@Component
public class ReadYml { @Value("${server.port}") private String port;@PostConstructpublic void postConstruct() { System.out.println("Read YML,port:" + port); }
}

在这里插入图片描述

6.3.2.2 .yml 详解

yml 是 YAML 是缩写,它的全称 Yet Another Markup Language 翻译成中⽂就是“另⼀种标记语⾔”。

  • yml 是⼀个可读性⾼,写法简单、易于理解,它的语法和 JSON 语⾔类似。
  • yml ⽀持更多的数据类型,它可以简单表达清单(数组)、散列表,标量等数据形态。它使⽤空⽩ 符号缩进和⼤量依赖外观的特⾊,特别适合⽤来表达或编辑数据结构、各种配置⽂件等。
  • yml ⽀持更多的编程语⾔,它不⽌是 Java 中可以使⽤在 Golang、PHP、Python、Ruby、 JavaScript、Perl 中。
  1. 语法
  • yml 是树形结构的配置⽂件,它的基础语法是“key: value”,注意 key 和 value 之间使⽤英⽂冒汗加空 格的⽅式组成的,其中的空格不可省略。在这里插入图片描述
  • 示例:使⽤ yml 连接数据库
spring:datasource:url: jdbc:mysql://127.0.0.0:3306/dbname?>characterEncoding=utf8 username: rootpassword: root

properties:
在这里插入图片描述
yml:
在这里插入图片描述

  1. yml 配置读取

yml 读取配置的⽅式和 properties 相同,使⽤ @Value 注解即可。

import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;@Component
public class ReadYml { @Value("${string.hello}") private String hello;@PostConstructpublic void postConstruct() { System.out.println("Read YML,Hello:" + hello); }
}

在这里插入图片描述

配置不同数据类型及 null:

# 字符串 
string.value: Hello#布尔值,true或false boolean.value: true boolean.value1: false# 整数
int.value: 10
int.value1: 0b1010_0111_0100_1010_1110 # ⼆进制# 浮点数
float.value: 3.14159
float.value1: 314159e-5 # 科学计数法# Null,~代表null 
null.value: ~
  • 配置字符串:
    字符串默认不⽤加上单引号或者双引号,如果加英⽂的单双引号可以表示特殊的含义。
  1. 字符串默认不⽤加上单引号或者双引号。
  2. 单引号会转义特殊字符,特殊字符最终只是⼀个普通的字符串数据。
  3. 双引号不会转义字符串⾥⾯的特殊字符;特殊字符会作为本身想表示的意思。

配置:

string:str1: Hello \n Spring Boot. str2: 'Hello \n Spring Boot.' str3: "Hello \n Spring Boot."

读取:

import org.springframework.beans.factory.annotation.Value; >import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;@Component
public class ReadYml { @Value("${string.str1}") private String str1;@Value("${string.str2}") private String str2;@Value("${string.str3}") private String str3;@PostConstructpublic void postConstruct() { System.out.println("string.str1:" + str1); System.out.println("string.str2:" + str2); System.out.println("string.str3:" + str3); }
}

执行结果:
在这里插入图片描述

  • 配置对象:
student: id: 1 name: Java age: 18
# 行内写法:
student: {id: 1,name: Java,age: 18}

读取对象: @ConfigurationProperties

# getter 和 setter ⽅法不能省略。import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@ConfigurationProperties(prefix = "student") 
@Component
public class StudentComponent {private int id;private String name;private int age;public int getId() { return id;}public void setId(int id) { this.id = id;}public String getName() { return name;}public void setName(String name) { this.name = name;}public int getAge() { return age;}public void setAge(int age) { this.age = age;}@Overridepublic String toString() { return "StudentComponent{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}';}
}

调用类:

@Component
public class ReadYml2 {@Autowiredprivate StudentComponent studentComponent;@PostConstructpublic void postConstruct() { System.out.println(studentComponent); }
}

执行结果;
在这里插入图片描述

配置集合:

dbtypes:name:- mysql- sqlserver - db2
# ⾏内写法
dbtypes: {name: [mysql,sqlserver,db2]}

读取集合: @ConfigurationProperties


@Component 
@ConfigurationProperties("dbtypes")
@Data
public class ListConfig { private List<String> name;
}

打印类:

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;@Component
public class ReadYml2 { @Autowiredprivate ListConfig listConfig;@PostConstruct
public void postConstruct() { System.out.println(listConfig.getName()); }
}
6.3.2.3 properties VS yml
  1. properties 是以 key=value 的形式配置的键值类型的配置⽂件,⽽ yml 使⽤的是类似 json 格式的 树形配置⽅式进⾏配置的,yml 层级之间使⽤换⾏缩进的⽅式配置,key 和 value 之间使⽤“: ”英⽂冒号加空格的⽅式设置,并且空格不可省略。
  2. properties 为早期并且默认的配置⽂件格式,但其配置存在⼀定的冗余数据,使⽤ yml 可以很好的 解决数据冗余的问题。
  3. yml 通⽤性更好,⽀持更多语⾔,如 Java、Go、Python 等,如果是云服务器开发,可以使⽤⼀份 配置⽂件作为 Java 和 Go 的共同配置⽂件。
  4. yml ⽀持更多的数据类型。

SpringMVC程序开发

什么是MVC

MVC 是 Model View Controller 的缩写,它是软件⼯程中的⼀种软件架构模式,它把软件系统分 为模型、视图和控制器三个基本部分。
在这里插入图片描述

  • Model(模型)是应⽤程序中⽤于处理应⽤程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
  • View(视图)是应⽤程序中处理数据显示的部分。通常视图是依据模型数据创建的。
  • Controller(控制器)是应⽤程序中处理⽤户交互的部分。通常控制器负责从视图读取数据, 控制⽤户输⼊,并向模型发送数据。

什么是SpringMVC

  • Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc),但它通常被称为“SpringMVC”。
  • MVC 是⼀种思想,⽽ Spring MVC 是对 MVC 思想的具体实现。总结来说,Spring MVC 是⼀个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架。既然是 Web 框架,那么当⽤户在浏览器中输⼊了 url 之后, Spring MVC 项⽬就可以感知到⽤户的请求。
  • Spring MVC 是 Spring 框架的核⼼模块,⽽ Spring Boot 是 Spring 的脚⼿架,绝⼤部分的 Java 项⽬约等于 Spring MVC 项⽬。
  • 在创建 Spring Boot 项⽬时,我们勾选的 Spring Web 框架其实就是 Spring MVC 框架。在这里插入图片描述

Spring MVC 创建和连接

Spring MVC 项⽬创建和 Spring Boot 创建项⽬相同(Spring MVC 使⽤ Spring Boot 的⽅式创建), 在创建的时候选择 Spring Web 就相当于创建了 Spring MVC 的项⽬。 Spring MVC 中使⽤ @RequestMapping 来实现 URL 路由映射,也就是浏览器连接程序的作⽤。

  1. 创建 Spring MVC 项⽬
    <<1>> Spring MVC 可以基于 Spring Boot 创建,也就是创建⼀个 Spring Boot 项⽬,勾选上 Spring Web 模块即可。在这里插入图片描述
    <<2>> 创建⼀个 UserController 类,实现⽤户到 Spring 程序的互联互通
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;@Controller // 让 spring 框架启动时,加载 
@ResponseBody // 返回⾮⻚⾯数据 
@RequestMapping("/user") // 路由器规则注册 
public class UserController {// 路由器规则注册 @RequestMapping("/hi")public String sayHi(){return "<h1>Hi,Spring MVC.</h1>"; }
}

<<3>> 当访问地址:http://localhost:8080/user/hi 时就能打印“hello,spring mvc”的信息了。

  • @RequestMapping 注解:
    @RequestMapping 是 Spring Web 应⽤程序中最常被⽤到的注解之⼀,它是⽤来注册接⼝的路 由映射的。所谓的路由映射指的是,当⽤户访问⼀个 url 时,将⽤户的请求对应到程序中某个类 的某个⽅法的过程就叫路由映射。
  • @RequestMapping 修饰类:
import com.example.demo.model.Person;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
@RequestMapping("/p")
public class PersonController { @RequestMapping("/index")public Object index(Person person){// 获取参数 System.out.println(person.getName() +":"+ person.getPassword());// 执⾏业务...return "/index.html";
}
}
  • @RequestMapping 修饰类+修饰⽅法,当修饰类和⽅法时,访问的地址是类 + ⽅法。
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import >org.springframework.web.bind.annotation.ResponseBody;@Controller
@ResponseBody // 定义返回的数据格式为⾮视图(text/html) 
public class UserController { @RequestMapping("/hi")public String sayHi(){return "<h1>Hi,Spring MVC.</h1>";}
}

⽅法地址:http://localhost:8080/hi

  • @RequestMapping默认接收GET请求,显示的指定 @RequestMapping 来接收 POST请求
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import >org.springframework.web.bind.annotation.RequestMethod; import >org.springframework.web.bind.annotation.ResponseBody;@Controller
@ResponseBody // 定义返回的数据格式为⾮⻚⾯
public class UserController {@RequestMapping(value = "/hi",method= RequestMethod.POST) public String sayHi(){return "<h1>Hi,Spring MVC.</h1>";}
}
  • GET请求的3种写法:
// 写法1 
@RequestMapping("/index")// 写法2
@RequestMapping(value = "/index",method = RequestMethod.GET)// 写法3 
@GetMapping("/index")
  • post 请求的 2 种写法:
// 写法1
@RequestMapping(value = "/index",method = RequestMethod.POST)// 写法2 
@PostMapping("/index")

获取参数

  • 传递单个参数

在 Spring MVC 中可以直接⽤⽅法中的参数来实现传参。

示例:

@RequestMapping("/m1")
public Object method_1(String name){ System.out.println("参数 name:"+name); return "/index.html";
}

在这里插入图片描述
程序的执⾏结果:
在这里插入图片描述

  • 传递对象

Spring MVC 可以⾃动实现参数对象的赋值
示例:

定义对象:

import lombok.Data;@Data
public class Person { private int id; private String name; private String password;
}

传递对象代码实现:

@RequestMapping("/m2")
public Object method_2(Person p){ System.out.println("对象中的 name:"+p.getName()); System.out.println("对象中的 password:"+p.getPassword()); return "/index.html";
}

前端访问:

在这里插入图片描述
最终执⾏结果:
在这里插入图片描述

  • 表单参数传递/传递多个参数(⾮对象)

当有多个参数时,前后端进⾏参数匹配时,是以参数的名称进⾏匹配的,因此参数的位置不影响后端获取参数的结果。

@RequestMapping("/m3")
public Object method_3(String name, String pwd) { System.out.println("name 参数:" + name); System.out.println("pwd 参数:" + pwd); return "/index.html";
}

前台访问地址:
在这里插入图片描述

  • 后端参数重命名(后端参数映射)

某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致,⽐如前端传递了⼀个 time 给后端,⽽后端⼜是有 createtime 字段来接收的,这样就会出现参数接收不到的情况,如果出现 这种情况,我们就可以使⽤ @RequestParam 来重命名前后端的参数值。

@RequestMapping("/m4")
public Object method_4(@RequestParam("time") String createtime) { System.out.println("时间:" + createtime);return "/index.html";
}

前端访问地址:

在这里插入图片描述

  • 设置必传参数:
    如果我们是前端传递⼀个⾮ time 的参数,就会出现程序报错的情况:
    在这里插入图片描述
    这是因为后端@RequestParam 注解已经声明了前端必须传递⼀个 time 的参数,但是前端没有给后端传递,查看 @RequestParam 注解的实现细节:在这里插入图片描述
  • ⾮必传参数设置

如果我们的实际业务前端的参数是⼀个⾮必传的参数,我们可以通过设置 @RequestParam 中的 required=false 来避免不传递时报错。

@RequestMapping("/m4")
public Object method_4(@RequestParam(value = "time", required = false) Stri ng createtime) {System.out.println("时间:" + createtime);return "/index.html";
}
  • @RequestBody 接收JSON对象
  • 在这里插入图片描述
    后端接收代码:
@RequestMapping(value = "/m5", method = RequestMethod.POST) public Object method_5(@RequestBody Person person) { System.out.println("Person:" + person);return "redirect:/index.html";
}
  • 获取URL中参数@PathVariable

后端实现代码:

@PostMapping("/m6/{name}/{password}")
public Object method_6(@PathVariable String name, @PathVariable String pass word) {System.out.println("name:" + name);System.out.println("password:" + password);return "redirect:/index.html";
}

前端⽅法地址:

@PostMapping(“/m6/{name}/{password}”) 中的 {password} 参数不能省略

在这里插入图片描述

  • 上传⽂件@RequestPart
@RequestMapping("/param9")
public String param9(String name, @RequestPart("myfile") MultipartFile fil e) throws IOException {// 获取⽂件后缀名String fileName = file.getOriginalFilename().substring(file.getOrigina lFilename().lastIndexOf("."));// ⽂件保存地址String filePath = ClassUtils.getDefaultClassLoader().getResource("stat ic").getPath() +"/" + UUID.randomUUID() + fileName;// 保存⽂件file.transferTo(new File(filePath));return filePath + " 上传成功.";
}

在这里插入图片描述

获取项⽬⽬录的⼏种⽅式:

ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX).getPath();new ClassPathResource("").getFile().getAbsolutePath(); ClassUtils.getDefaultClassLoader().getResource("").getPath(); ResourceUtils.getFile("classpath:static/").getPath();
  • 获取 Request 和 Response 对象
@RequestMapping("/param10")
public String param10(HttpServletResponse response, HttpServletRequest requ est) {String name = request.getParameter("name");// 获取所有 cookie 信息Cookie[] cookies = request.getCookies();return name + " 你好.";
}
  • 传统获取 header/cookie
@RequestMapping("/param10")
@ResponseBody
public String param10(HttpServletResponse response, HttpServletRequest requ est) {String name = request.getParameter("name");// 获取所有 cookie 信息Cookie[] cookies = request.getCookies();String userAgent = request.getHeader("User-Agent");return name + ":"+userAgent;
}
  • 简洁的获取 Cookie—@CookieValue
@RequestMapping("/cookie")
@ResponseBody
public String cookie(@CookieValue("bite") String bite) { return "cookie:" + bite;
}
  • 简洁获取 Header—@RequestHeader
@RequestMapping("/header")
@ResponseBody
public String header(@RequestHeader("User-Agent") String userAgent) { return "userAgent:"+userAgent;
}
  • Session 存储和获取
    Session 存储:
@RequestMapping("/setsess")
@ResponseBody
public String setsess(HttpServletRequest request) {// 获取 HttpSession 对象,参数设置为 true 表示如果没有 session 对象就创建⼀个 sessionHttpSession session = request.getSession(true);if(session!=null){session.setAttribute("username","java");}return "session 存储成功";
}

读取 Session :

@RequestMapping("/sess")
@ResponseBody
public String sess(HttpServletRequest request) {// 如果 session 不存在,不会⾃动创建HttpSession session = request.getSession(false);String username = "暂⽆";if(session!=null && session.getAttribute("username")!=null){ username = (String) session.getAttribute("username");}return "username:"+username;
}
  • 获取 Session 更简洁的⽅式:
@RequestMapping("/sess2")
@ResponseBody
public String sess2(@SessionAttribute(value = "username",required = false) String username) {return "username:"+username;
}

返回数据

默认请求下⽆论是 Spring MVC 或者是 Spring Boot 返回的是视图 (xxx.html),⽽现在都是前后端分离的,后端只需要返给给前端数据即可,这个时候我们就需要使⽤ @ResponseBody 注解了。

@ResponseBody 返回的值如果是字符会转换成 text/html,如果返回的是对象会转换成 application/json 返回给前端。
@ResponseBody 可以⽤来修饰⽅法或者是修饰类,修饰类表示类中的所有⽅法都会返回 html 或者 json,⽽不是视图。

组合注解:@RestController,@RestController = @Controller + @ResponseBody。

  • 返回静态⻚⾯
    <<1>> 创建前端⻚⾯ 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>hello,spring mvc</title><script src="index.js"></script>
</head>
<body><h1>Hello,Spring MVC.</h1>
</body>
</html>

创建控制器 controller:

import com.example.demo.model.Person;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
@RequestMapping("/p")
public class PersonController { @RequestMapping("/index") public Object index(){ // 执⾏业务...// 返回view -> index.html return "/index.html";}
}
  • 返回 text/html
@RequestMapping("/m7") @ResponseBody
public String method_7() { return "<h1>Hello,HTML~</h1>";
}

在这里插入图片描述
在这里插入图片描述

示例:实现计算器功能

使⽤ postman 传递参数,或使⽤ form 表单的⽅式提交参数。

前端⻚⾯:

<!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><form action="http://localhost:8080/calc/sum"><h1>计算器</h1>数字1<input name="num1" type="text"><br>数字2<input name="num2" type="text"><br><input type="submit" value=" 点击相加 "></form>
</body>
</html>

controler代码:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.ResponseBody;@ResponseBody
@Controller
@RequestMapping("/calc")
public class CalcController {@RequestMapping("/sum")public String sum(Integer num1,Integer num2){return String.format("<h1>计算的结果是:%d</h1><a href='javascript:h istory.go(-1);'>返回</a>",num1+num2);}
}
  • 返回 JSON 对象
@RequestMapping("/m8")
@ResponseBody
public HashMap<String, String> method_8() { HashMap<String, String> map = new HashMap<>(); map.put("Java", "Java Value"); map.put("MySQL", "MySQL Value"); map.put("Redis", "Redis Value");return map;
}

在这里插入图片描述
在这里插入图片描述
示例:实现登录功能,前端使⽤ ajax,后端返回 json 给前端

后端代码:

@RequestMapping(value = "/login")@ResponseBodypublic HashMap<String,Object> login(String username, String password){ HashMap<String,Object> res = new HashMap<>();int succ = 200;if(username!=null && password!=null && username.equals("admin") && password.equals("admin")){ res.put("msg","登录成功");}else{res.put("msg","登录失败");}res.put("succ",succ);return res;}

前端代码:

<!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"><script src="js/jquery-1.9.1.min.js"></script> <title>Document</title><script>function mysub() {var username = jQuery("#username").val();var password = jQuery("#password").val(); jQuery.getJSON("/user/login",{"username":username, "password":password},function (result) {if(result.succ==200){ alert("返回结果:"+result.msg);}else{alert("操作失败,请重试。");}});}</script>
</head>
<body><div style="text-align: center;"><h1>登录</h1>⽤户:<input id="username"><br>密码:<input id="password" type="password"><br><input type="button" value=" 提交 " onclick="mysub()" style="margin -top: 20px;margin-left: 50px;"></div>
</body>
</html>
  • 请求转发或请求重定向
// 请求重定向 
@RequestMapping("/index")
public String index(){return "redirect:/index.html";
}// 请求转发 
@RequestMapping("/index2")
public String index2(){return "forward:/index.html";
}

转发是服务器帮转的,⽽重定向是让浏览器重新请求另⼀个地址
请求重定向(redirect)将请求重新定位到资源;请求转发(forward)服务器端转发。
请求重定向地址发⽣变化,请求转发地址不发⽣变化。
请求重定向与直接访问新地址效果⼀直,不存在原来的外部资源不能访问;请求转发服务器端转发有可能造成原外部资源不能访问。

请求转发 forward 导致问题演示:

请求转发如果资源和转发的⻚⾯不在⼀个⽬录下,会导致外部资源不可访问。

@Controller
@RequestMapping("/user")
public class UserController { @RequestMapping(value = "/index") public String sayHi(){ return "forward:/index.html"; }
}

程序的⽬录:
在这里插入图片描述
程序的执⾏结果:
在这里插入图片描述
将转发 foward 换成重定向 redirect,⻚⾯就可以正常获取到外部资源 js 了。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody;@Controller
@RequestMapping("/user")
public class UserController { @RequestMapping(value = "/index") public String sayHi(){ return "redirect:/index.html"; }
}

综合示例:
示例一:使⽤ ajax 实现登录功能,⽆需连接数据库,如果⽤户名和密码都是 root,则显示登录成功,可以直 接访问 main ⻚⾯,否则显示登录失败。每次访问 main ⻚⾯时,验证是否已经登录,如果登录了显示 欢迎信息,否则让⽤户先去登录⻚⾯登录。
示例二:带头像功能的注册功能实现。

6.4 SpringBoot 单元测试

什么是单元测试?

单元测试(unit testing),是指对软件中的最⼩可测试单元进⾏检查和验证的过程就叫单元测试。
单元测试是开发者编写的⼀⼩段代码,⽤于检验被测代码的⼀个很⼩的、很明确的(代码)功能是否正确。执⾏单元测试就是为了证明某段代码的执⾏结果是否符合我们的预期。如果测试结果符合我们的预 期,称之为测试通过,否则就是测试未通过(或者叫测试失败)。

  • 可以⾮常简单、直观、快速的测试某⼀个功能是否正确
  • 使⽤单元测试可以帮我们在打包的时候,发现⼀些问题,因为在打包之前,所以的单元测试必须通 过,否则不能打包成功。
  • 使⽤单元测试,在测试功能的时候,可以不污染连接的数据库,也就是可以不对数据库进⾏任何改 变的情况下,测试功能。

6.4.1 Spring Boot 单元测试使用

Spring Boot 项⽬创建时会默认单元测试框架 spring-boot-test,⽽这个单元测试框架主要是依靠另⼀ 个著名的测试框架 JUnit 实现的, Spring Boot 项⽬创建时⾃动添加。

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope>
</dependency>

spring-boot-starter-test 的 MANIFEST.MF⾥⾯有具体的说明:在这里插入图片描述

  1. ⽣成单元测试类
    在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
    最终⽣成的代码:
import org.junit.jupiter.api.Test;class UserControllerTest {@Test void save() {}
}

这个时候,此⽅法是不能调⽤到任何单元测试的⽅法的,此类只⽣成了单元测试的框架类,具体的业务 代码要⾃⼰填充。

  1. 添加单元测试代码
    <<1>> 添加 Spring Boot 框架测试注解:@SpringBootTest
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class UserControllerTest {@Test void save() {}
}

<<2>> 添加单元测试业务逻辑

import com.example.demo.model.User;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import javax.annotation.Resource;@SpringBootTest
class UserControllerTest {@Resourceprivate UserController userController;@Testvoid save() {User user = new User(); user.setId(1);user.setName("Java Test"); user.setPassword("123");boolean result = userController.save(user); // 使⽤断⾔判断最终的结果是否符合预期 Assertions.assertEquals(true, result); //        Assertions.assertTrue(result);}
}

如果断⾔失败,则后⾯的代码都不会执⾏在这里插入图片描述

6.8 SpringBoot 日志文件

6.8.1 日志的功能

  • 发现和定位问题
  • 记录⽤户登录⽇志,⽅便分析⽤户是正常登录还是恶意破解⽤户
  • 记录系统的操作⽇志,⽅便数据恢复和定位操作⼈
  • 记录程序的执⾏时间,⽅便为以后优化程序提供数据⽀持

6.8.2 日志的使用

Spring Boot 内置了⽇志框架,默认情况下使⽤的是 info ⽇志级别将⽇志输出到控制台的。
在这里插入图片描述

6.8.3⾃定义⽇志打印

  1. 在程序中得到⽇志对象

在程序中获取⽇志对象需要使⽤⽇志⼯⼚ LoggerFactory。
在这里插入图片描述

Logger 对象是属于 org.slf4j 包下的,不要导⼊错包,Spring Boot 中内置了⽇志框架 Slf4j,可以直接在程序中调⽤ slf4j 来输出⽇志。在这里插入图片描述

代码示例:

private static Logger logger = LoggerFactory.getLogger(UserController.class );
  1. 使⽤⽇志对象打印⽇志
// 2.使⽤⽇志打印⽇志 
logger.info("--------------要输出⽇志的内容----------------");

在这里插入图片描述
在这里插入图片描述

6.8.4⽇志级别

6.8.4.1 ⽇志级别的作用
  1. ⽇志级别可以帮你筛选出重要的信息,⽐如设置⽇志级别为 error,那么就可以只看程序的报错⽇ 志了,对于普通的调试⽇志和业务⽇志就可以忽略了,从⽽节省开发者信息筛选的时间。
  2. ⽇志级别可以控制不同环境下,⼀个程序是否需要打印⽇志,如开发环境我们需要很详细的信息, ⽽⽣产环境为了保证性能和安全性就会输⼊尽量少的⽇志,⽽通过⽇志的级别就可以实现此需求。
6.8.4.2 ⽇志级别的分类
  • trace:微量,少许的意思,级别最低
  • debug:需要调试时候的关键信息打印
  • info:普通的打印信息(默认⽇志级别)
  • warn:警告,不影响使⽤,但需要注意的问题
  • error:错误信息,级别较⾼的错误⽇志信息
  • fatal:致命的,因为代码异常导致程序退出执⾏的事件

越往上接收到的消息就越少,如设置了 warn 就只能收到 warn、error、fatal 级别的⽇志了。
在这里插入图片描述

6.8.4.3 ⽇志级别的设置

⽇志级别配置只需要在配置⽂件中设置“logging.level”配置项即可。⽇志的输出级别,默认是 info。

示例:


logging: level: root: error
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;@RestController 
@RequestMapping("/user") 
public class UserController {// 1.得到⽇志对象private static Logger logger = LoggerFactory.getLogger(UserController.class);@Value("${server.port}") private String port;@Value("${spring.datasource.url}") private String url;@RequestMapping("/sayhi") public String sayHi() { // 2.使⽤⽇志打印⽇志logger.trace("================= trace ==============="); logger.debug("================= debug ==============="); logger.info("================= info ===============");logger.warn("================= warn ==============="); logger.error("================= error ===============");return "Hi," + url; }
}
6.8.4.4 日志持久化

在⽣产环境上咱们需要将⽇志保存下来,以便出现问题之后追 溯问题,把⽇志保存下来的过程就叫做持久化。在配置⽂件中指定⽇志的存储⽬录或者是指定⽇志保存⽂件名之后, Spring Boot 就会将控制台的⽇志写到相应的⽬录或⽂件下了。

示例一:

# 设置⽇志⽂件的⽬录
logging:file:path: D:\\home\\ruoyi
# 设置⽇志⽂件的⽂件名
logging:file:name: D:\\home\\ruoyi\\spring-1204.log

示例二:
controller 包下 error 级别以上的⽇志保存到 log_all.log 下,将 service 下 warn 级别以上的⽇志保存到 log_all.log 下。

  • 实现的关键步骤:
    不同包定义不同的⽇志级别。
    使⽤⽇志对象打印所有类型的⽇志。
    设置固定的⽇志保存⽂件名。
6.8.4.5 使用Lombok输出日志

使⽤ @Slf4j 注解,在程序中使⽤ log 对象即可输⼊⽇志,并且只能使⽤ log 对象才能输出, 这是 lombok 提供的对象名。

  1. 添加 lombok 依赖
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <optional>true</optional> 
</dependency>
  1. 输出⽇志
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;@RestController 
@RequestMapping("/p")
@Slf4j
public class PersonController {@RequestMapping("/log")public void loggerTest() { log.error("------------------- error -----------------"); }
}

lombok 原理
在这里插入图片描述
打开target目录可以看到:
在这里插入图片描述
在这里插入图片描述
lombok 的更多注解:
在这里插入图片描述在这里插入图片描述在这里插入图片描述

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

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

相关文章

JAVA WEB 能够实现整个文件夹的上传下载吗?

导入项目&#xff1a; 导入到Eclipse&#xff1a;导入项目 导入到IDEA&#xff1a;导入项目 springboot统一配置&#xff1a;springboot-配置 下载示例&#xff1a; https://gitee.com/xproer/up6-jsp-eclipse/tree/6.5.40/ 工程 NOSQL NOSQL示例不需要任何配置&#xff0c;可…

【面试经典150 | 】最长递增子序列

文章目录 Tag题目来源解题思路方法一&#xff1a;动态规划 写在最后 Tag 【动态规划】【数组】 题目来源 300. 最长递增子序列 解题思路 方法一&#xff1a;动态规划 定义状态 dp[i] 表示以位置 i 对应整数为末尾的最长递增子序列的长度。 状态转移 我们从小到大计算 dp…

FASTAPI系列 16-其他响应类型

FASTAPI系列 16-其他响应类型 文章目录 FASTAPI系列 16-其他响应类型前言一、HTMLResponse 响应 HTML二、纯文本响应三、另外的JSON 响应四、FileResponse文件五、StreamingResponse六、RedirectResponse 重定向请求总结更多内容&#xff0c;请关注公众号, 发送666 更可以得到免…

解决配置文件中文乱码

一、问题 二、解决方法

HTML5+CSS3小实例:文字边框视觉错位

实例:文字边框视觉错位 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scal…

StringRedisTemplate与RedisTemplate详解【序列化的方式不同】

spring 封装了 RedisTemplate 对象来进行对redis的各种操作&#xff0c;它支持所有的 redis 原生的 api。在RedisTemplate中提供了几个常用的接口方法的使用&#xff0c;分别是: private ValueOperations<K, V> valueOps; private HashOperations<K, V> hashOps; …

TLSR8258 MTU、DLE(PDU)

本文基于泰凌微TLSR8258 M1S1 demo。 1.DLE&#xff1a;LE Data Packet Length Extension 中文全称&#xff1a;低功耗蓝牙数据包长度扩展。 这是一个在2014年12月2日正式发布的bluetooth for BLE添加的新特性&#xff0c;以支持在LL Data PDU更长的数据&#xff0c;最大支持…

自己编译SQLite或将SQLite移植到新的操作系统(六)

返回&#xff1a;SQLite—系列文章目录 上一篇:SQLite中的动态内存分配&#xff08;五&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 1.0 引言 对于大多数应用程序&#xff0c;推荐的构建方法 SQLite是使用合并代码 文件 sqlite3.c 及其相应的头文件 sqlite3.…

刚刚,百度和苹果宣布联名

百度 Apple 就在刚刚&#xff0c;财联社报道&#xff0c;百度将为苹果今年发布的 iPhone16、Mac 系统和 iOS18 提供 AI 功能。 苹果曾与阿里以及另外一家国产大模型公司进行过洽谈&#xff0c;最后确定由百度提供这项服务&#xff0c;苹果预计采取 API 接口的方式计费。 苹果将…

Jenkins用户角色权限管理

Jenkins作为一款强大的自动化构建与持续集成工具&#xff0c;用户角色权限管理是其功能体系中不可或缺的一环。有效的权限管理能确保项目的安全稳定&#xff0c;避免敏感信息泄露。 1、安装插件&#xff1a;Role-based Authorization Strategy 系统管理 > 插件管理 > 可…

Docker 哲学 - Dockerfile 指令

Dockerfile 的 entrypoint 和 cmd 书写方式一样吗&#xff0c;分别用一个node项目的 demo来举例 Dockerfile 的 entrypoint 、cmd 有什么区别&#xff0c;分别举例他们同时出现的场景和 单独出现的场景 entrypoint 和 cmd 命令&#xff1a; 同时出现&#xff1a; 1、cmd 作为 e…

【教程】iOS如何抓取HTTP和HTTPS数据包经验分享

&#x1f4f1; 在日常的App开发和研发调研中&#xff0c;对各类App进行深入的研究分析时&#xff0c;我们需要借助专业的抓包应用来协助工作。本文将介绍如何使用iOS手机抓包工具来获取HTTP和HTTPS数据包&#xff0c;并推荐一款实用的抓包应用——克魔助手&#xff0c;希望能够…

快速上手Pytrch爬虫之爬取某应图片壁纸

一、前置知识 1 爬虫简介 网络爬虫&#xff08;又被称作网络蜘蛛、网络机器人&#xff0c;在某些社区中也经常被称为网页追逐者)可以按照指定的规则&#xff08;网络爬虫的算法&#xff09;自动浏览或抓取网络中的信息。 1.1 Web网页存在方式 表层网页指的是不需要提交表单&…

《数据结构学习笔记---第三篇》---单链表具体实现

目录 1.链表 1.1 链表的概念及结构 2.不带头单链表的实现 2.1创建头文件“SList.h” 2.2 创建具体接口实现文件SList.c 2.2.1打印 2.2.2申请链表结点 2.2.3创建一个长度为n的链表 2.2.4尾插尾删 2.2.5头插头删 2.2.6寻找x元素&#xff0c;返回pos 2.2.7插入和删除pos…

量子专家联合开展欧洲之星项目“SupremeQ”以实现光量子计算优势

内容来源&#xff1a;量子前哨&#xff08;ID&#xff1a;Qforepost&#xff09; 编辑丨王珩 编译/排版丨浪味仙 沛贤 深度好文&#xff1a;1800字丨10分钟阅读 近日&#xff0c;英国全栈光量子计算系统公司 ORCA Computers、德国单光子探测器提供商 Pixel Photonics、丹麦量…

餐饮服务升级:微信小程序扫码点餐制作

餐饮体验的升级不仅体现在食物的质量和环境的营造上&#xff0c;更在于服务的便捷性和智能化。扫码点餐小程序正是这一理念的体现&#xff0c;它通过简化点餐流程&#xff0c;为顾客和商家带来了双赢的局面。那么商家微信小程序扫码点餐制作的流程是怎么样呢&#xff1f;怎么快…

二叉树的遍历及线索二叉树试题解析

一、单项选择题 01.在下列关于二叉树遍历的说法中&#xff0c;正确的是( C ). A.若有一个结点是二叉树中某个子树的中序遍历结果序列的最后一个结点&#xff0c;则它一定是该子树的前序遍历结果序列的最后一个结点 B.若有一个结点是二叉树中某个子树的前序遍历结果序列的最后一…

安卓国内ip代理app,畅游网络

随着移动互联网的普及和快速发展&#xff0c;安卓手机已经成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;由于地理位置、网络限制或其他因素&#xff0c;我们有时需要改变或隐藏自己的IP地址。这时&#xff0c;安卓国内IP代理App便成为了一个重要的工具。虎观代理…

Chrome之解决:浏览器插件不能使用问题(十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

c语言知识点整理------基础c语言框架,数据类型,变量常量,注释

前言 本文不涉及讲解原理&#xff0c;用简洁明了的风格&#xff0c;去整理方便查阅的知识点。 &#xff08;适合有编程基础&#xff0c;或者需要作为笔记的人群使用&#xff09; 程序基本框架 结果会输出hello world。 程序的执行 c语言属于编译型语言。 代码执行分为五个…