day65_66_SpringBoot

image-20230624230313370

一、引言


1.1 初始化配置

为了使用SSM框架去开发,准备SSM框架的模板配置。

1.2 整合第三方框架

为了Spring整合第三方框架,单独的去编写xml文件。

1.3 后期维护

后期SSM项目后期xml文件特别多,维护xml文件的成本是很高的

1.4 部署工程

SSM工程部署也是很麻烦,依赖第三方的容器

1.5 敏捷式开发

基于Java的SSM开发方式是很笨重,而现在的python,php,NodeJS的敏捷式开发已经盖过Java一头

二、SpringBoot介绍


SpringBoot是由Pivotal团队研发的,SpringBoot并不是一门新技术,只是将之前常用的Spring,SpringMVC,data-jpa等常用的框架封装到了一起,帮助你隐藏这些框架的整合细节,实现敏捷开发。 约定大于配置

例如:

我们需要搭建一个spring web项目的时候需要怎么做呢?

1)配置web.xml,加载spring和spring mvc

2)配置数据库连接、配置spring事务

3)配置加载配置文件的读取,开启注解

4)配置日志文件

配置完成之后部署tomcat 调试


有了SpringBoot后,只需要导入xxx-start依赖,写上Controller-service-Mapper代码,启动就行

SpringBoot就是一个工具集。

官网:https://spring.io/projects/spring-boot

SpringBoot特点:

  • SpringBoot项目不需要模板化的配置。
  • SpringBoot中整合第三方框架时,只需要导入相应的starter依赖包,就自动整合了。约定大于配置。
  • SpringBoot默认只有一个.properties的配置文件,不推荐使用xml,后期会采用.java的文件去编写配置信息。
  • SpringBoot工程在部署时,采用的是jar包的方式,内部自动依赖Tomcat容器,提供了多环境的配置。
  • 后期要学习的微服务框架SpringCloud需要建立在SpringBoot的基础上。

三、SpringBoot快速入门【重点


3.1 快速构建SpringBoot

3.1.1 选择构建项目的类型

选择构建项目的类型
image-20230624230840419

注意:根据网络状况,可能会提示无法连接。如果不能连接,使用http://start.springboot.io(或者https://start.aliyun.com)

3.1.2 指定SpringBoot版本和需要的依赖

指定SpringBoot版本和需要的依赖
image-20230624231046116

ps: 2.7.13版本创建完项目会报错alimaven找不到依赖,手动将pom文件中版本改成2.7.2

<parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>2.7.2</version>
 <relativePath/> 
</parent>

3.1.3 导入依赖

会自动导入的…

<dependencies>
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
 </dependency>

 <dependency>
     <groupId>org.projectlombok</groupId>
     <artifactId>lombok</artifactId>
     <optional>true</optional>
 </dependency>
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-test</artifactId>
     <scope>test</scope>
 </dependency>

3.1.4 编写了Controller

@RestController
public class TestController {

    @GetMapping("/test")
    public String test(){
 return "Hello SpringBoot!";
    }
}

3.1.5 测试

主类点击启动项目

image-20230624233626353

效果
image-20230624233656863image-20230624233731294

3.2 SpringBoot的目录结构

3.2.1 pom.xml文件

  • 指定了一个父工程: 指定当前工程为SpringBoot,帮助我们声明了starter依赖的版本。
  • 项目的元数据:包名,项目名,版本号。
  • 指定了properties信息:指定了java的版本为1.8
  • 导入依赖:默认情况导入spring-boot-starter,spring-boot-starter-test
  • 插件:spring-boot-maven-plugin

3.2.2 .gitignore文件

默认帮我们忽略了一些文件和目录,避免提交到Git仓库中

3.2.3 src目录

-src
  -main	  
    -java
      -包名
 启动类.java			# 需要将controller类,放在启动类的子包中或者同级包下,否则需要使用@ComponentScan 注解,并指定扫描的包即可
    -resources
      -static				  # 存放静态资源的,js,css,html
      -templates			  # 存储模板页面的,Thymeleaf,jsp,freemarker
      application.properties  # SpringBoot提供的配置文件,后缀支持2种:1.properties 2.yml(推荐)
  -test   				      # 只是为了测试用的

3.3 SpringBoot三种启动方式

3.3.1 运行启动类的main方法

运行main方法即可

image-20230625165933293

3.3.2 maven命令

mvn spring-boot:run

image-20230625165908735

3.3.3 采用jar包的方式运行

将当前项目打包成一个jar文件,并通过java -jar jar文件

1 通过maven命令将项目打成jar包

image-20230625170234958

2 在磁盘找到该jar包,执行java命令

image-20230625170333971

PS: 部署到linux服务器,也是这么操作的(打包,放服务器,启动,访问)

四、SpringBoot常用注解【重点


4.1 @Configuration和@Bean

  • 之前使用SSM去开发时,在xml文件中编写bean标签,但是SpringBoot不推荐使用xml文件。

  • @Configuration注解相当于beans标签

  • @Bean注解相当于bean标签

  • id=“方法名 | 注解中的name属性(优先级更高)”

  • class=“方法的返回结果”

@AllArgsConstructor
@NoArgsConstructor
@Data
@ToString
public class User {

    private int id;
    private String username;
    private String password;
    private String sex;
    private Date birthday;

}
//===================================================
@Configuration   // 代表当前类是一个配置类
public class UserConfig {  
    @Bean      // 构建一个实例,放到spring容器中
    public User user(){
      return new User(1,"张三丰","123456","男",new Date());
    }
    
    /*
    <beans ....>     @Configuration
 <bean id="user1" class="com.qf.firstspringboot.entity.User" />
    </beans>
     */
}

// ==================================================
// 就可以从容器中获得该对象
@RestController
public class TestController {

    @Autowired
    private User user;

    @GetMapping("/bean")
    public User testBean(){
 return user;
    }
}

image-20230625215715245

4.2 @SpringBootApplication

@SpringBootApplication就是一个组合注解:

  • @SpringBootConfiguration就是@Configuration注解,代表启动类就是一个配置类。
  • @EnableAutoConfiguration帮你实现自动装配的,SpringBoot工程启动时,运行一个SpringFactoriesLoader的类,加载META-INF/spring.factories配置类(已经开启的),通过SpringFactoriesLoader中的load方法,以for循环的方式,一个一个加载。
    • 好处:无需编写大量的整合配置信息,只需要按照SpringBoot提供好了约定去整合即可。
    • 坏处:如果说你导入了一个starter依赖,那么你就需要填写他必要的配置信息。
    • 手动关闭自动装配指定内容:@SpringBootApplication(exclude = QuartzAutoConfiguration.class)
  • @ComponentScan就相当于<context:component-scan basePackage=“包名” />,帮助扫描注解的。

4.3 @ComponentScan

约定大于配置

SpringBoot默认配置组件扫描,扫描的是与主类平级以及以下的包结构


如果真要扫描一些特殊位置

可以给主类加@ComponentScan(“包路径”)来指定扫描路径

五、SpringBoot常用配置【重点


5.1 SpringBoot的配置文件格式

SpringBoot的配置文件,文件名必须是application,格式支持propertiesyml

更推荐使用yml文件格式:

  1. yml文件,会根据换行和缩进帮助咱们管理配置文件所在位置

  2. yml文件,相比properties更轻量级一些

  3. K: V 表示一对键值对(冒号: 后一定有一个空格)

  4. 以空格的缩进来控制层级关系;只要是左对齐的都是属于一个层级的数据

  5. 属性和值大小写敏感.

yml文件的劣势:

  1. 严格遵循换行和缩进

  2. 在填写value时,一定要在: 后面跟上空格

配置文件的作用

  • 修改SpringBoot的配置的默认值:

    ​ 比如默认启动的Tomcat的端口是8080,可以修改为8081

propertiesyml
image-20230625220509355image-20230625220524979

配置文件的位置:

  • 一般默认都是放在resources/下
  • 也有其他位置的,暂且不讨论

5.2 多环境配置

实际开发中,有三种环境:

1.开发环境-程序员日常开发所需

2.测试环境-项目的集成测试

3.生产环境-最终项目部署的环境,真实环境

SpringBoot支持多环境的配置。只需要根据环境需要,编写多个配置文件,通过配置属性选择使用哪个环境

使用步骤:

1.多环境的配置文件命名:application-环境名.yml

2.在总文件application.yml中通过属性:spring profiles active 环境名

image-20230625221539596

ps:也可在部署工程时,通过 java -jar jar文件 --spring.profiles.active=环境

5.3 获取配置文件信息

场景: …

解释: 将yml配置的值,赋值给对应的类

方案:

  • 方案一: @ConfigurationProperties
  • 方案二: @Value

方案一: @ConfigurationProperties [了解]

# 示例
aliyun:
 accessKey: *******
 accessSecret: *******
@Data
@Component
@ConfigurationProperties(prefix = "aliyun") // yml中的前缀
public class AliyunProperties {
    // yml中的key
    private String accessKey; 
    private String accessSecret;

}
// java代码中使用AliyunProperties对象即可获得数据
@RestController
public class TestController {

    @Autowired
    private AliyunProperties aliyun;


    @GetMapping("/yml")
    public AliyunProperties testGetYmlValue(){
 return aliyun;
    }

}

image-20230625222751082

方案二: @Value [推荐]

// yml配置文件内容是一样的
// 不一样的是Java类中使用的注解
@Data
@Component
public class AliyunProperties {

    @Value("${aliyun.accessKey}")
    private String accessKey;

    @Value("${aliyun.accessSecret}")
    private String accessSecret;

}

5.4 热加载

5.4.1 导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>

5.4.2 settings配置

修改settings中的配置
image-20230625223935285

5.4.3 设置

编辑界面同时 ctrl+shift+alt+/ 选择registry,勾选自动部署

勾选自动部署
image-20230625224058755

注意,要以debug方式启动,代码写完,光标离开idea 过1-3秒钟就会自动更新…

六、SpringBoot的WEB开发

SpringBoot是自动配置的,只要在pom文件中加入对应的web开发依赖

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

就会自动配置关于web开发的内容,比如路径匹配规则,项目名,端口,静态资源访问等等

6.1 映射匹配

加入web依赖后,SpringBoot自动配置的映射路径为 / ,通过源码可以查看

// DispatcherServletAutoConfiguration类 line117-125

@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
               WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
    // 创建DispatcherServlet注册的Bean
    // 参数2 getServlet().getPath() 点进去getPath()方法
    DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,webMvcProperties.getServlet().getPath());
    registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
    registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
    multipartConfig.ifAvailable(registration::setMultipartConfig);
    return registration;
}
// WebMvcProperties.java 类
public static class Servlet {

    /**
	 * Path of the dispatcher servlet. Setting a custom value for this property is not
	 * compatible with the PathPatternParser matching strategy.
	 */
    // 拦截路径为/
    private String path = "/";

    /**
	 * Load on startup priority of the dispatcher servlet.
	 */
    private int loadOnStartup = -1;

    public String getPath() {
 return this.path;
    }
    // ...
}

基于以上源码:可以看出,我们可以通过在全局配置文件中 使用

spring.mvc.servlet.path=/api

spring:
 mvc:
  servlet:
   path: /api

修改默认访问路径,但是鸡肋的是不能写通配符,比如*.do这种…

ps: 如果真要设置*.do这种后缀匹配,需要额外自定义配置类,修改默认设置,暂略

image-20230625230643462

6.2 添加项目名

springboot 项目一般直接地址加端口就可以访问了,不像放在tomcat里面还需要加上项目名。现在,想访问的时候加上项目名用来区分,只要在配置文件里面加上

server:
   servlet:
     context-path: /myapp

6.3 访问静态资源

在开发web项目时,需要引入大量的js,css,图片等静态资源,SpringBoot默认将静态资源存放在classpath:下,目录名须符合如下规则:

  • classpath:/static/ #[推荐]
  • classpath:/public/
  • classpath:/resources/
  • classpath:/META-INF/resources/

源码WebProperties.java中88行

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
				"classpath:/resources/", "classpath:/static/", "classpath:/public/" };

此处的classpath:就是指根路径,即resources下

我们一般推荐,在resources下创建static文件夹来存放静态资源

测试

我们在项目的src/main/resources下创建static文件夹放一张图片,在地址栏中输入http://localhost:8080/图片名,如果在浏览器上显示图片则代表配置成功

欢迎页: index.html

默认在以上静态资源路径中名字叫做index.html的都是欢迎页

image-20230625232217141

源码已经看到了,当然也可以通过源码中的样子修改默认位置 (不推荐)

spring:
  web:
    resources:
      static-locations: classpath:/jingtai

6.4 视图渲染

在上边的案例中我们使用通过@ResponseBody或@RestController注解向页面返回Json数据,那么如果我们需要渲染html页面该怎么做呢?

controller层的代码像springmvc那样,方法的返回值设计成String,就能跳转页面了

只不过只能跳转至/resources/static下的html页面

注意: SpringBoot默认不支持jsp页面,因为推荐使用同为模板引擎的Thymeleaf

image-20230625234515184

请求转发和重定向也和springmvc中使用方式一样

    @GetMapping("/ok1")
    public String toOK1(){
        return "forward:/ok.html";
    }

    @GetMapping("/ok2")
    public String toOK2(){
        return "redirect:/ok.html";
    }

6.5 拦截器

用法基本与springmvc用法一致

  • 编写自定义拦截器类
  • 实现接口
  • 重写拦截方法
  • 配置拦截器
    • 这个不一样,以前是配置在springmvc.xml中,现在SpringBoot推荐使用java类的方式配置

自定义拦截器类

@Component
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 System.out.println("my preHandle");
 // false  所有都拦截,排除在外的不拦截
 return false;
    }

}

拦截器配置类

@Configuration // !!!加注解!!!!配置类
public class MyConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
 // addPathPatterns 定义拦截的路径
 // excludePathPatterns 定义放行的路径
 // 这两个方法支持不定长参数,可以设置多个拦截/放行路径
 registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/test");
    }
}

测试即可

6.6 全局异常

SpringBoot中有一个ControllerAdvice的注解,使用该注解表示开启了全局异常的捕获,我们只需在自定义一个方法使用ExceptionHandler注解然后定义捕获异常的类型即可对这些捕获的异常进行统一的处理。

// @ControllerAdvice
// public class MyGlobalExceptionHandler {
//
//     @ExceptionHandler(value =Exception.class)
//     public String exceptionHandler(Exception e){
//  System.out.println("未知异常!原因是:"+e);
//  return e.getMessage();
//     }
//
// }
@RestControllerAdvice  // RestControllerAdvice是返回的JSON数据
public class MyGlobalExceptionHandler {

    @ExceptionHandler(value =Exception.class)
    public ResultData exceptionHandler(Exception e){
 System.out.println("未知异常!原因是:"+e);
 return ResultData.fail(e.getMessage());
    }

}

测试

@RestController
public class TestController {
    @GetMapping("/test")
    public String test(){
 System.out.println(1/0 );
 return "Hello SpringBoot!";
    }
}

image-20230626002817274

6.7 RESTful【重点

RESTful(Representational State Transfer)是一种用于设计网络应用程序的架构风格。它由Roy Fielding于2000年在他的博士论文中引入,并成为构建Web服务和API(应用程序编程接口)的常用方式。

RESTful架构的原则基于资源的概念,这些资源通过唯一的URL(统一资源定位符)进行标识。可以使用标准的HTTP方法(如GET、POST、PUT、DELETE等)来访问和操作这些资源。每个资源以定义良好的格式进行表示,通常使用JSON(JavaScript对象表示)或XML(可扩展标记语言)。

RESTful架构的关键原则包括:

  1. 无状态(Stateless):服务器在请求之间不保留任何客户端状态。每个客户端请求必须包含处理所需的所有必要信息,包括需要的身份验证凭据(如果需要)。
  2. 客户端-服务器(Client-Server):客户端和服务器是独立的实体,通过网络进行通信。客户端负责用户界面和用户交互,而服务器管理数据存储和处理。
  3. 统一接口(Uniform Interface):客户端和服务器之间的接口遵循一组统一的约定,包括使用标准化的HTTP方法、基于资源的URL和标准媒体类型表示。这使得系统具有解耦和互操作性。
  4. 可缓存(Cacheable):服务器的响应可以由客户端或中间服务器缓存,以提高性能并减少网络负载。
  5. 分层系统(Layered System):架构可以由多个层组成,每个层隐藏其下层的复杂性。这允许可扩展性、模块化和关注点分离。
  6. HATEOAS(Hypermedia as the Engine of Application State):服务器在响应中提供超媒体链接,用于指导客户端可用的操作和状态转换。这使得系统更易于发现和自我描述。

实现RESTful API涉及设计资源、定义访问这些资源的URL和HTTP方法,并指定数据交换的表示格式。API应该有良好的文档,遵循RESTful原则,并对客户端请求提供清晰和有意义的响应。

由于其简单性、可扩展性和平台无关性,RESTful架构已经得到广泛采用。它允许开发灵活和互操作的系统,并可以轻松集成到各种平台和编程语言中。

  • R: Representational(表述性):REST资源实际上可以用各种形式来进行表述,包括XML,JSON,甚至HTML即最适合资源使用者的任意形式.

  • S:State(状态): 当使用REST的时候,我们更关注资源的状态而不是对资源采取的行为

  • T:Transfer(转移): REST涉及到转移资源数据,它以某种表述性的形式从一个应用转移到另一个应用.

​ 在REST中,资源通过URL进行识别和定位.REST的行为是以HTTP的方法来定义的.具体的说就是GET,POST,PUT,DELETE,PATCH以及其他方法的HTTP方法构成了REST中的动作.

说点人话…

  • 使用不同的请求方式代表要做的事

  • 使用合适的url路径代表资源位置

    • http://localhost:8080/user/1
普通(url)RESTFul更推荐
查询/getEmp/emp --> get/emp/1 --> get
添加/addEmp?xx=zz&aa=bb/emp --> post/emp/save --> post
修改/editEmp?id=1&xx=zz&aa=bb/emp/1 --> put/emp/edit/1 --> put
删除/deleteEmp?id=1/emp/1 --> delete/emp/del/1 --> delete

springboot支持RESTful

  • @PathVariable 截取路径中的参数
  • @RestController 因为每个方法都返回json数据,需要每个方法都加上@ResponseBody,现在只需要在类上加上@RestController,每个方法都返回JSON数据
  • @GetMapping 处理get请求,一般用于查询数据
  • @PostMapping 处理post请求,一般用于添加数据
  • @PutMapping 处理put请求,一般用于更新数据
  • @DeleteMapping处理delete请求,一般用于删除数据

演示

七、整合Mybatis+Druid【重点


7.1 xml方式整合Mybatis

xml方式在编写复杂SQL时,更适合

7.1.1 环境

mybatis和druid的springboot环境下的依赖

<!-- mysql驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

<!-- druid连接 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>

<!-- mybatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>

准备数据库

create table `emp` (
  `id` int(11) auto_increment,
  `username` varchar(30) default null,
  `age` int(11) default null,
  `birthday` date default null,
primary key (`id`)
) engine=innodb default charset=utf8;

-- ----------------------------
-- Records of emp
-- ----------------------------
insert into `emp` values (1, '李四', '19', '1990-01-01');
insert into `emp` values (2, '王五', '20', '2019-01-03');
insert into `emp` values (3, '张三', '18', '2019-01-01');
insert into `emp` values (4, '赵六', '21', '2019-05-15');

实体类

@AllArgsConstructor
@NoArgsConstructor
@Data
@ToString
public class Employee {
    private int id;
    private String username;
    private int age;
    private Date birthday;
}

7.1.2 编写接口和映射文件

public interface EmployeeMapper {
    List<Employee> findAll();
}

在resources/下创建mapper文件夹,在其内创建mapper映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.taotie.testspringboot.mapper.EmployeeMapper">


    <select id="findAll" resultType="Employee">
        select * from emp
    </select>
</mapper>

tip: mapper文件名不能叫EmpMapper.xml…裂开

image-20230626181334754

7.1.3 yaml文件

# mybatis配置
mybatis:
  # 扫描映射文件
  mapper-locations: classpath:mapper/*.xml
  # 配置别名扫描的包
  type-aliases-package: com.taotie.testspringboot.entity
  configuration:
    # 开启驼峰映射配置
    map-underscore-to-camel-case: true
# 连接数据库的信息
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://url:3306/test_springboot?serverTimezone=UTC
    username: ******
    password: *****
    type: com.alibaba.druid.pool.DruidDataSource

7.1.4 扫描mapper

主类扫描mapper

@SpringBootApplication
@MapperScan("com.taotie.testspringboot.mapper")
public class TestSpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestSpringbootApplication.class, args);
    }
}

7.1.5 测试

@RestController
public class TestMybatisController {

    @Autowired
    private EmployeeMapper employeeMapper;

    @GetMapping("/m1")
    public ResultData testMybatis1() {
        List<Employee> list = employeeMapper.findAll( );
        return ResultData.ok(list);
    }
}

7.2 注解方式整合Mybatis[了解]

注解方式在编写配置简单,简单SQL推荐使用

create table `dept`  (
  `deptno` varchar(255),
  `dname` varchar(255) ,
  `loc` varchar(255) ,
  primary key (`deptno`)
) ;

-- ----------------------------
-- Records of dept
-- ----------------------------
insert into `dept` values ('10', 'ACCOUNTING', 'NEW YORK');
insert into `dept` values ('20', 'RESEARCH', 'DALLAS');
insert into `dept` values ('30', 'SALES', 'CHICAGO');
insert into `dept` values ('40', 'OPERATIONS', 'BOSTON');
@AllArgsConstructor
@NoArgsConstructor
@Data
@ToString
public class Dept {
    private String deptno;
    private String dname;
}

7.2.1 Mapper接口

@Mapper
public interface DeptMapper {

    @Select("select * from dept")
    List<Dept> findAll();

}

7.2.2 添加Mybatis注解

针对增删改查:@Insert,@Delete,@Update,@Select

还是需要在启动类中添加@MapperScan注解

@Mapper
public interface EmpMapper {
    @Select("select * from emp where id = #{id}")
    public Emp getEmpById(int id); // 查一个

    @Insert("insert into emp (name,age,birthday) values (#{name},#{age},#{birthday})")
    public int insertEmp(Emp emp);// 增

    @Delete("delete from emp where id = #{id}")
    public int deleteEmpById(int id);//删

    @Update("update emp set name=#{name},age=#{age},birthday=#{birthday} where id=#{id}")
    public int updateEmpById(Emp emp);//改

}

7.2.3 添加日志配置

# yml文件
logging:
  level:
    com.taotie.testspringboot.mapper: DEBUG

7.2.4 测试,查看日志

@SpringBootApplication
@MapperScan("com.taotie.testspringboot.mapper")
public class TestSpringbootApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestSpringbootApplication.class, args);
    }
}
// ============================================
@RestController
public class TestMybatisController {
   
    @Autowired
    private DeptMapper deptMapper;

    @GetMapping("/m2")
    public ResultData testMybatis2() {
        List<Dept> list = deptMapper.findAll( );
        return ResultData.ok(list);
    }
}

7.3 SpringBoot整合分页助手

7.3.1 导入依赖

<!-- pageHelper依赖-->
<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper-spring-boot-starter</artifactId>
	<!-- 不能使用1.2.6版本,因为版本太低与springboot高版本不兼容,导致启动项目报错 -->
	<version>1.4.2</version>
</dependency>

7.3.2 测试使用


    @GetMapping("/m2")
    public ResultData testMybatis2() {
        PageHelper.startPage(1,2);
        List<Dept> list = deptMapper.findAll( );
        PageInfo<Dept> info = new PageInfo<>(list);

        return ResultData.ok(info);
    }

八、SpringBoot整合日志

8.1 日志框架

slf4j

slf4j 只是一个日志标准,并不是日志系统的具体实现。它用于提供日志操作的接口,提供获取日志对象的方法

log4j

apache 实现的一个开源日志组件

logback

相对于logback,有更好的特性,springboot默认使用logback

log4j2

是 log4j的升级版本,拥有更好的性能,支持异步日志

注意:slf4j属于日志接口,log4j、logback、log4j2属于日志实现

springboot默认使用logcak处理日志,本例中,使用log4j2处理日志

8.2 日志的等级

日志级别按照从低到高为:

ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF

程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少

All:最低等级,会输出所有日志记录

Trace:追踪,就是程序推进一下

Debug:调试日志

Info:消息日志,可用于输出应用程序的运行过程

Warn:输出警告级别的日志

Error:输出错误信息日志

Fatal:输出每个严重的错误日志.

OFF:最高等级的,用于关闭所有日志记录

8.3 整合Log4j2

8.3.1 实现配置文件

在resources下面新建log4j2.xml,输入以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!-- status log4j2内部输出自身的日志信息的级别 -->
<!-- configuration中主要包括有 Properties、Appenders、Loggers标签 -->
<configuration status="INFO">
    <!-- 全局参数 -->
    <Properties>
        <Property name="pattern">%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p %c{1}:%L -%m%n</Property>
        <Property name="displayName">饕餮</Property>
    </Properties>
    <!-- 输出源,常见的主要有Console、RollingFile、File 三种子节点
      Console:用于定义输出到控制台的Appender
      File:用于定义输出到指定位置的文件的Appender
      RollingFile:定义指定方式触发新的Appender
    -->
    <Appenders>
        <Console name="console" target="SYSTEM_OUT" follow="true">
            <PatternLayout>
                <pattern>${pattern}</pattern>
            </PatternLayout>
        </Console>
        <!-- 文件 每次运行程序会自动清空,由append属性决定 -->
        <!--<File name="error" fileName="${displayName}_error.log" append="false">-->
        <!--&lt;!&ndash; 指定error 级别的日志 &ndash;&gt;-->
        <!--<ThresholdFilter level="ERROR" onMatch="ACCEPT"-->
        <!--onMismatch="DENY" />-->
        <!--<PatternLayout>-->
        <!--<pattern>${pattern}</pattern>-->
        <!--</PatternLayout>-->
        <!--</File>-->
        <!-- 滚动文件 -->
        <!--<RollingFile name="rollingFile" fileName="${displayName}.log"-->
        <!--filePattern="${displayName}_%d{yyyy-MM-dd}.log">-->
        <!--<PatternLayout>-->
        <!--<pattern>${pattern}</pattern>-->
        <!--</PatternLayout>-->
        <!--&lt;!&ndash; 按大小划分 &ndash;&gt;-->
        <!--<SizeBasedTriggeringPolicy size="50 MB" />-->
        <!--</RollingFile>-->
    </Appenders>
    <!-- 主要配置Root、Logger两种标签 -->
    <Loggers>
        <!--
            Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等
            Logger标签内还可以配置一个或多个AppenderRef属性
        -->
        <Logger name="org.springframework" level="INFO" />
        <Logger name="org.mybatis" level="DEBUG" />
        <!-- 每个配置都必须有一个根记录器Root,默认所有的Logger都继承此配置 -->
        <Root level="DEBUG">
            <!-- AppenderRef 用来指定该日志输出到哪个Appender -->
            <AppenderRef ref="console"></AppenderRef>
            <!--
            <AppenderRef ref="error"></AppenderRef>
            <AppenderRef ref="rollingFile"></AppenderRef>
            -->
        </Root>
    </Loggers>
</configuration>

8.3.2 代码中使用日志

log4j2 的依赖包随着搭建springboot,自动导入,无需再导入

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
@RestController
public class TestLogController {
   // import org.apache.logging.log4j.LogManager;
   // import org.apache.logging.log4j.Logger;
    private Logger logger = LogManager.getLogger(TestLogController.class);

    @GetMapping("/log")
    public ResultData log() {
        logger.warn("我是警告");
        logger.info("我是消息");
        logger.error("我是错误!");
        return ResultData.ok( );
    }
}

image-20230627192419365

注意:实际开发中,不允许使用输出语句定位问题,需要采用debug要么就是日志

九、SpringBoot整合Knife4j

9.1 接口文档

开发中一般写接口文档比较麻烦,需要定义访问路径,请求方式,请求参数,请求列表,请求参数实例,返回结果,返回结果类型,返回体结构,返回结构实例,返回参数列表,返回状态码列表等等等等等…

关键还会经常随着需求的更新而改变…

还有,就是这玩意儿真的手写起来太费劲,且不好分工,前端说这东西是后端写的,后端是这东西是前端写的…

这是一个手写的word版的接口文档…

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hpYcgOy7-1688895141627)(https://qiushiju-tuchuang.oss-cn-hangzhou.aliyuncs.com/%E6%8E%A5%E5%8F%A3%E6%96%87%E6%A1%A31.png)]

这是华为的接口文档实例

获取数据标准_数据治理中心 DataArts Studio_API参考_数据架构API_数据标准接口_华为云 (huaweicloud.com)

9.2 接口文档工具

正是有这样那样的问题,才催生了这些接口文档工具,可以方便的生成接口文档,还可以当接口测试工具去测试,还可以导出成pdf,word,markdown, 太舒服了

常见的工具:

  • Swagger (丝袜哥er)
  • Knife4j (乃夫 for j)

它们之间的关系是:

Swagger是一个开源框架,用于设计、构建和文档化API。它提供了一组工具和规范,可以生成具有交互式界面的API文档。Swagger可以通过注解或配置文件来定义API的元数据,包括请求和响应的数据结构、参数、路径等。它还支持自动生成客户端代码和执行API测试。

Knife4j是一个基于Swagger的增强工具,为Swagger文档提供了更直观、美观和易于使用的界面。它通过自定义样式和感知能力来改进Swagger生成的文档。Knife4j提供了一些额外的功能,如开发者友好的文档展示、在线测试工具、接口权限管理等。它可以轻松集成到Spring Boot等框架中,提供更好的API文档展示和管理体验。

因此,Knife4j可以看作是Swagger的一个扩展和增强工具,通过提供更好的UI和功能来改进Swagger生成的API文档。它使用Swagger的核心功能和规范,并在此基础上进行了定制和改进,提供更好的用户体验和开发者工具。

swagger的界面

s1

s2

Knife4j的界面

k1

k2

9.3 整合Knife4j

9.3.1 依赖

        <!--  接口文档 -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>

9.3.2 yaml配置

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://ip:3306/test_springboot?serverTimezone=UTC&useSSL=false
    username: root
    password: ***
    type: com.alibaba.druid.pool.DruidDataSource
  mvc:
    pathmatch:    # Springfox使用的路径匹配是基于AntPathMatcher的
                    # 所以需要配置此参数
      matching-strategy: ant_path_matcher

9.3.3 Controller接口加注解

@RestController
@RequestMapping("/api/dept/")
@Api(tags = "部门接口")
public class TestKnife4jController {

    @Autowired
    private DeptMapper mapper;

    @GetMapping("/list")
    @ApiOperation(value = "查询所有部门")
    public ResultData test(){
        List<Dept> list = mapper.findAll( );
        return ResultData.ok( list );
    }

    @GetMapping("/{id}")
    @ApiOperation(value = "根据部门编号查询部门")
    public ResultData findById(@PathVariable String id){
        Dept dept = mapper.findById(id);
        return ResultData.ok( dept );
    }

    @PostMapping("/save1")
    @ApiOperation(value = "插入部门-表单")
    public ResultData save1(Dept dept){
        mapper.save(dept);
        return ResultData.ok( );
    }

    @PostMapping("/save2")
    @ApiOperation(value = "插入部门-json")
    public ResultData save2(@RequestBody Dept dept){
        mapper.save(dept);
        return ResultData.ok( );
    }

}

9.3.4 启动项目,访问接口文档

http://localhost:8080/doc.html

image-20230627201725175

image-20230627201814062

可以测试

image-20230627201921140

image-20230627202113129

bug

image-20230630154313098

image-20230630154430368

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>最新版</version>
</dependency>

9.4 详细配置

主页信息

package com.taotie.testspringboot.config;

import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
@Configuration
@EnableSwagger2
public class Knife4jConfiguration {

    /**
     * 是否开启swagger
     */
    @Value("${swagger.enabled}")
    private boolean enabled;

    @Bean
    public Docket defaultApi2() {
        String groupName = "3.X版本";
        Docket docket = new Docket(DocumentationType.OAS_30)
                // 是否启用Swagger
                .enable(enabled)
                .apiInfo(new ApiInfoBuilder()
                .title("这是Taotie-Test-knife4j API ")
                .description("项目描述")
                .termsOfServiceUrl("服务器URL")
                .contact(new Contact("饕餮", null, "qiushiju0828@163.com"))
                .version("3.0")
                .build())
                //分组名称
                .groupName(groupName)
                .select()
                // 这里指定Controller扫描包路径,没有加注解的接口方法也会生成接口文档
                // .apis(RequestHandlerSelectors.basePackage("com.taotie.testspringboot.controller"))

                // 这里指定只有加了注解的才会生成接口文档 (推荐)
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }
}

image-20230627204318203

设置是否开启接口文档,因为生产环境是不需要接口文档的

application.yml文件中设置开关

# Swagger配置
swagger:
  # 是否开启swagger
  enabled: true

image-20230627204241342

改成false后,访问api文档没有接口

image-20230627204408971

9.5 其他注解

  • @Api:修饰整个类,描述Controller的作用

    @Api(tags ="用户管理API")
    public class UserController {}
    
  • @ApiOperation:描述一个类的一个方法,或者说一个接口

    @ApiOperation(value="获取用户详细信息", notes="根据id来获取用户详细信息")
    public ResultData<User> findUserById(Integer id){}
    
  • @ApiModel:用对象来接收参数 ,修饰类

  • @ApiModelProperty:用对象接收参数时,描述对象的一个字段

    例如:

    @ApiModel(description = "用户实体类")
    public class User {
        @ApiModelProperty(name="id", value="用户id")
        private Integer id;
        @ApiModelProperty(value="用户姓名")
        private String name;
    
  • @ApiResponse:HTTP响应其中1个描述

  • @ApiResponses:HTTP响应整体描述,一般描述错误的响应

    // 针对响应状态 修饰方法
    @ApiResponses({
                @ApiResponse(code=500, message = "服务器异常")
        })
    
  • @ApiIgnore:使用该注解忽略这个API

    @ApiError :发生错误返回的信息

    @ApiParam:单个参数描述,用在控制器的方法上

    @ApiImplicitParam:一个请求参数,用在方法上

    @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Integer", paramType = "path")
    
    @ApiImplicitParams({
                @ApiImplicitParam(),
                @ApiImplicitParam()
        })
    
  • 针对返回值,使用泛型表示

    @ApiModel
    public class ResultData {
    
        @ApiModelProperty(value = "返回数据状态",notes = "200成功 500失败")
        private int code;
        @ApiModelProperty(value = "返回数据",notes = "可以是具体的对象,也可以是null")
        private Object data;
    

十、SpringBoot项目部署

SpringBoot项目端口改成8888再部署,因为阿里云服务器之前部署过tomcat,端口8080已经在用

10.1 pom.xml添加配置

<!-- 
	解决服务器启动项目时报出
      boot-01-1.0-SNAPSHOT.jar中没有主清单属性的错
-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.7.2</version>
            </plugin>
        </plugins>
    </build>

10.2 打成jar包

image-20230629005034585

10.3 上传服务器

cd /usr/local

image-20230629005051554

10.4 启动

java -jar /usr/local/test-springboot-0.0.1-SNAPSHOT.jar

image-20230629005216495

ps: 之前阿里云部署过tomcat服务器,端口8080已经在用,我们SpringBoot项目改端口成8888再打包部署,另阿里云服务器要开放8888端口

访问测试

image-20230629005440738

image-20230629005454633

image-20230629005551435

注意:这样启动存在问题,前台形式启动,finalshell不能关闭,一旦程序就停止

linux系统 按照端口查进程

  • 安装工具 yum -y install lsof
  • lsof -i:端口
  • image-20230630160300625
  • 杀死进程
  • kill -9 18722

10.5 后台启动

服务器执行以下命令

[root@x local]# mkdir -p /usr/local/project/logs/
[root@x local]# nohup java -jar /usr/local/test-springboot-0.0.1-SNAPSHOT.jar  > /usr/local/project/logs/test-springboot.log &

# 不要盲目赋值,看好项目名是不是一样
# 别忘了最后有一个&符号

image-20230629010013531

测试访问
",notes = “200成功 500失败”)
private int code;
@ApiModelProperty(value = “返回数据”,notes = “可以是具体的对象,也可以是null”)
private Object data;




# 十、SpringBoot项目部署

SpringBoot项目端口改成8888再部署,因为阿里云服务器之前部署过tomcat,端口8080已经在用

## 10.1 pom.xml添加配置

```xml
<!-- 
  解决服务器启动项目时报出
    boot-01-1.0-SNAPSHOT.jar中没有主清单属性的错
-->
  <build>
      <plugins>
          <plugin>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-maven-plugin</artifactId>
              <version>2.7.2</version>
          </plugin>
      </plugins>
  </build>

10.2 打成jar包

[外链图片转存中…(img-4ILGLi3s-1688895141631)]

10.3 上传服务器

cd /usr/local

[外链图片转存中…(img-h5S5CSp7-1688895141631)]

10.4 启动

java -jar /usr/local/test-springboot-0.0.1-SNAPSHOT.jar

[外链图片转存中…(img-kldzLiBu-1688895141631)]

ps: 之前阿里云部署过tomcat服务器,端口8080已经在用,我们SpringBoot项目改端口成8888再打包部署,另阿里云服务器要开放8888端口

访问测试

[外链图片转存中…(img-rG449rul-1688895141632)]

[外链图片转存中…(img-Sn34w1Pi-1688895141632)]

[外链图片转存中…(img-qECgx2Lk-1688895141632)]

注意:这样启动存在问题,前台形式启动,finalshell不能关闭,一旦程序就停止

linux系统 按照端口查进程

  • 安装工具 yum -y install lsof
  • lsof -i:端口
  • [外链图片转存中…(img-4e5uixjx-1688895141633)]
  • 杀死进程
  • kill -9 18722

10.5 后台启动

服务器执行以下命令

[root@x local]# mkdir -p /usr/local/project/logs/
[root@x local]# nohup java -jar /usr/local/test-springboot-0.0.1-SNAPSHOT.jar  > /usr/local/project/logs/test-springboot.log &

# 不要盲目赋值,看好项目名是不是一样
# 别忘了最后有一个&符号

[外链图片转存中…(img-XMgQMTMz-1688895141633)]

测试访问

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值