springboot 入门

发布时间:2024年01月15日

学习目标:

掌握springboot项目创建及日常开发流程,能够独立进行项目创建、接口开发、接口调试等工作。了解ideal的常用配置及快捷键


学习内容:

一、创建springboot项目

? ? ? ? ideal创建项目时可以用spring initializr会自动添加springboot依赖,也可以创建普通的maven项目,自己手动引入依赖。

? ? ? ? 1、使用spring initializr创建springboot项目

????????依次点击菜单?File?->New->Project,选择spring initializr

?????????当前start.spring.io只提供了springboot3以上版本。springboot依赖本机的jdk版本,对应关系如下:https://zhuanlan.zhihu.com/p/652895555

? ? ? ?选择所需的依赖,点击创建后会自动生成项目目录及入口application类和application.properties配置文件

? ? ? ? 2、创建普通maven项目,手动引入依赖

? ? ? ? 依次点击菜单?File?->New->Project,选择Maven Archetype,Archetype选择org.apache.maven.archetypes:maven-archetype-webapp

pom文件中添加依赖

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

? ? ? ? maven依赖包版本管理有三种方式

? ? ? ? 1)、支持继承自parent

? ? ? ? ?2)、使用dependencyManagement

? ? ? ? 3)、直接指定版本

?

? ? ? ? 在src/main目录下手动创建java目录、包目录及application入口类,在src/resource目录下创建application.yml配置文件

? ? ? ? 创建启动类BootDemoApplication

package sccba.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BootDemoApplication {

    public static void main(String[] args) {

        SpringApplication.run(BootDemoApplication.class, args);
    }

}

? ? ? ?创建配置文件application.yaml,指定端口及访问跟路径

server:
  port: 6371
  context-path: /

???????? springboot支持在不同的目录中存在多个配置文件,它的读取顺序是:
1、config/application.properties(项目根目录中config目录下)
2、config/application.yml
3、application.properties(项目根目录下)
4、application.yml
5、resources/config/application.properties(项目resources目录中config目录下)
6、resources/config/application.yml
7、resources/application.properties(项目的resources目录下)
8、resources/application.yml

????????顺序可以通过实验验证:
1~8 个位置 分别定义不同的 server 端口号 8001~8008即可验证结果顺序
????????注:
1、如果同一个目录下,有application.yml也有application.properties,默认先读取application.properties。
2、如果同一个配置属性,在多个配置文件都配置了,默认使用第1个读取到的,后面读取的不覆盖前面读取到的。
3、创建SpringBoot项目时,一般的配置文件放置在项目的resources目录下,因为配置文件的修改,通过热部署不用重新启动项目,而热部署的作用范围是classpath下。

二、开发helloworld接口

? ? ? ? 新建controller包,在controller包下创建HelloController类

@RestController
@RequestMapping("/hi")
public class HelloController {

    @GetMapping("/hello")
    public String hello(String name) {
        return "hello," + name + ",welcome to springboot ";
    }

}

????????启动BootDemoApplication

? ? ? ? 在浏览器访问hello接口http://localhost:8001/hi/hello?name=sccba

1、@Controller、@Service、@Repository、@Component 注解的类会纳入 Spring 容器中进行管理.

2、@Controller 用于标注控制层组件;@Service 用于标注业务层组件;@Repository 用于标注数据持久化层组件;@Component 泛指组件,用于标注不好归类的组件。

3、默认情况 bean 的名称为类名(首字母小写),可以通过 value 属性自定义 bean 的名称。默认情况下 bean 是单例的,可以使用 @Scope 注解指定。

4、如果不使用springMVC时,@Controller、@Service、@Component 三者使用其实是没有什么差别的,但如果使用了springMVC,@Controller就被赋予了特殊的含义。spring会遍历上面扫描出来的所有bean,过滤出那些添加了注解@Controller的bean,将Controller中所有添加了注解@RequestMapping的方法解析出来封装成RequestMappingInfo存储到RequestMappingHandlerMapping中的mappingRegistry。后续请求到达时,会从mappingRegistry中查找能够处理该请求的方法。

5、对于 Spring Boot 项目,启动类会默认标记 @SpringBootApplication 注解,它的内部依赖了 @ComponentScan 注解:默认启动类同目录下(./**/*)任意子孙包中类上的注解都会被自动扫描,启动类上级目录下类中的注解默认是无法自动扫描到的(此时可以在启动类上自定义扫描路径:@ComponentScan(value = "com.wmx"))。

三、配置swagger与knife4j

????????pom.xml引入依赖

        <!--swagger,访问地址/swagger-ui/index.html-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>3.0.0</version>
        </dependency>

? ? ? ? 在applicaton.xml中添加配置

spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher #Spring Boot 2.6及以后,swagger配置报错,需添加此配置

#============swagger3.0配置,访问地址/swagger-ui/index.html==========
swagger:
  enabled: true

????????添加swagger配置类

package sccba.example.config;

import io.swagger.annotations.Api;
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.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.ArrayList;


@Configuration
@EnableOpenApi
public class SwaggerConfig {
    /**
     * 用于读取配置文件 application.properties 中 swagger 属性是否开启,默认值false
     */
    @Value(value = "${swagger.enabled:false}")
    Boolean swaggerEnabled;

    @Bean
    public Docket docket() {
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                // 是否开启swagger
                .enable(swaggerEnabled)
                .select()
                /**
                 * RequestHandlerSelectors,配置要扫描接口的方式
                 * basePackage指定要扫描的包
                 * any()扫描所有,项目中的所有接口都会被扫描到
                 * none()不扫描
                 * withClassAnnotation()扫描类上的注解
                 * withMethodAnnotation()扫描方法上的注解
                 */
                // 过滤条件,扫描指定路径下的文件
                .apis(RequestHandlerSelectors.basePackage("sccba.example.admin.controller")
                        .or(RequestHandlerSelectors.basePackage("sccba.example.blog.controller")))
                //加了Api注解的类,才生成接口文档
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                //加了ApiOperation注解的方法,才生成接口文档
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
//                 指定路径处理,PathSelectors.any()代表不过滤任何路径
//                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        /*作者信息*/
        Contact contact = new Contact("sccba", "https://sccba.org", "7aaaaaaa");
        return new ApiInfo(
                "Spring Boot 集成 Swagger3 测试",
                "Spring Boot 集成 Swagger3 测试接口文档",
                "v1.0",
                "https://sccba.org",
                contact,
                "Apache 2.0",
                "http://www.apache.org/licenses/LICENSE-2.0",
                new ArrayList()
        );
    }
}

? ? ? ? 重启BootDemoApplication,在浏览器输入swagger访问的地址:http://localhost:8001/swagger-ui/index.html

? ? ? ? 配置knife4j,在pom.xml添加依赖

        <!--knife4j,访问地址/doc.html-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>

? ? ? ? 在application.yml添加配置

#==============knife4j配置,访问地址http://localhost:6371/doc.html===========
knife4j:
  # 开启增强配置
  enable: true
  # 开启生产环境屏蔽
  production: false

? ? ? ? 重启?BootDemoApplication,在浏览器输入swagger访问的地址:http://localhost:8001/doc.html

四、mybatis配置

? ? ? ? 在pom.xml添加依赖

        <!--        数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        <!--mybatis-plus依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>

? ? ? ? 在application.yml添加配置


spring:
  datasource:
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://4.10.12.17:3306/boot_demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456

mybatis-plus:
  ## 这个可以不用配置,因其默认就是这个路径
  mapper-locations: classpath:/mapper/*Mapper.xml
  #实体扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: sccba.example.*.dao
  global-config:
    # 数据库相关配置
    db-config:
      #主键类型  AUTO:"数据库ID自增", INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
      id-type: AUTO
      #字段策略 IGNORED:"忽略判断",NOT_NULL:"非 NULL 判断"),NOT_EMPTY:"非空判断"
      field-strategy: not_empty
      #驼峰下划线转换
      column-underline: true
      #数据库大写下划线转换
      #capital-mode: true
      #逻辑删除配置
      logic-delete-value: 0
      logic-not-delete-value: 1
      db-type: h2
    #刷新mapper 调试神器
    refresh: true
  # 原生配置
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false

? ? ? ??mapper-locations指定了mapper.xml的配置路径,typeAliasesPackage指定了扫描的实体类包路径。在相应路径下创建***Mapper类及***Mapper.xml

package sccba.example.admin.dao;

import org.apache.ibatis.annotations.Mapper;
import sccba.example.admin.domain.entity.UserDO;

/**
 * 根据习惯不同命名可能是***Dao ***PO ***Mapper
 */
@Mapper
public interface UserMapper {
    UserDO get(Long id);
}
<?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="sccba.example.admin.dao.UserMapper">

    <select id="get" resultType="sccba.example.admin.domain.entity.UserDO">
		select * from user where id = #{value}
	</select>

</mapper>

五、DO、DTO、BO、VO、POJO定义和转换

分层领域模型规约:

?DO(Data Object):此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。

?DTO(Data Transfer Object):数据传输对象,Service 或 Manager 向外传输的对象。

?BO(Business Object):业务对象,由 Service 层输出的封装业务逻辑的对象。

??VO(View Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象。

?Query:数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装,禁止

使用 Map 类来传输。

分层使用和转换(个人理解)
controller层:接受前端的VO,DTO;接受service层BO,DTO;向前端发送VO,DTO

service层:接受controller层VO,DTO,BO;接受dao层的DO,DTO;向controller层返回BO,DTO

dao层:接受service层的VO,DTO,BO,DO;从数据库查询DO;向service层返回DO

? ? ? ? UserDO

package sccba.example.admin.domain.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @ClassName UserDO
 * @Description 此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
 * @Author chenqiang
 * @Date 2024/1/9 10:19
 * @Version 1.0
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDO {
    private Long id;

    private String name;
    /**
     * vo 中没有 password 字段
     */
    private String password;

    private Integer age;

    private String tel;

    private Long depId;
}

? ? ? ? ?UserDTO

package sccba.example.admin.domain.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


/**
 * @ClassName UserDTO
 * @Description 后端内部传输用,例如多张表字段合并到一个对象
 * @Author chenqiang
 * @Date 2024/1/9 11:19
 * @Version 1.0
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDTO {

    private Long id;

    private String name;

    private Integer age;

    private String tel;

    private Long depId;
}

? ? ? ? UserVO?

package sccba.example.admin.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @ClassName UserVO
 * @Description 显示层对象,通常是 Web 向模板渲染引擎层传输的对象。
 * @Author chenqiang
 * @Date 2024/1/9 10:19
 * @Version 1.0
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("用户实体类")
public class UserVO {
    @ApiModelProperty(value = "姓名", required = true, example = "联盟")
    private String name;

    @ApiModelProperty(value = "年龄", required = true, example = "20")
    private Integer age;

    @ApiModelProperty(value = "电话", required = true, example = "12345665555")
    private String tel;

    @ApiModelProperty(value = "部门", required = true, example = "研发部")
    private String depName;
}

? ? ? ? UserQuery

package sccba.example.admin.domain.query;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @ClassName UserQuery 数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装
 * @Description TODO
 * @Author c_see
 * @Date 2024/1/11 10:50
 * @Version 1.0
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserQuery {
    private Long userId;
    private Long depId;
}

? ? ? ? UserTransfer,定义数据转换类进行各个领域对象间的转换,使用ideal插件GenerateO2O快速生成代码。

package sccba.example.admin.domain.transfer;

import sccba.example.admin.domain.dto.UserDTO;
import sccba.example.admin.domain.entity.UserDO;
import sccba.example.admin.domain.vo.UserVO;

/**
 * @ClassName UserTransfer
 * @Description 定义转换工具类
 * @Author c_see
 * @Date 2024/1/12 16:02
 * @Version 1.0
 **/
public class UserTransfer {

    public static UserDTO toDTO(UserDO userDO) {
        if (userDO == null) {
            return null;
        }
        UserDTO userDTO = new UserDTO();
        userDTO.setId(userDO.getId());
        userDTO.setName(userDO.getName());
        userDTO.setAge(userDO.getAge());
        userDTO.setTel(userDO.getTel());
        userDTO.setDepId(userDO.getDepId());
        return userDTO;
    }

    public static UserVO toVO(UserDTO userDTO) {
        if (userDTO == null) {
            return null;
        }
        UserVO userVO = new UserVO();
        userVO.setName(userDTO.getName());
        userVO.setAge(userDTO.getAge());
        userVO.setTel(userDTO.getTel());
        return userVO;
    }
}

? ? ? ? ?UserService

package sccba.example.admin.service;

import sccba.example.admin.domain.dto.UserDTO;

public interface UserService {

    public UserDTO getById(Long userId);

}

? ? ? ? UserServiceImpl

package sccba.example.admin.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import sccba.example.admin.dao.UserMapper;
import sccba.example.admin.domain.dto.UserDTO;
import sccba.example.admin.domain.entity.UserDO;
import sccba.example.admin.domain.transfer.UserTransfer;
import sccba.example.admin.service.UserService;

/**
 * @ClassName UserServiceImpl
 * @Description TODO
 * @Author c_see
 * @Date 2024/1/12 15:27
 * @Version 1.0
 **/
@Service(value = "userService")
public class UserServiceImpl implements UserService {

    @Autowired //根据类型注入
    private UserMapper userMapper;

    @Override
    public UserDTO getById(Long userId) {
        UserDO userDO = userMapper.get(userId);

        //TODO 内部使用UserBO封装中间所需的逻辑对象,可以包括一个或多个其它的对象。常见操作DO转DTO,DO转BO、BO转DTO

        return UserTransfer.toDTO(userDO);
    }
}

? ? ? ? UserController

package sccba.example.admin.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.*;
import sccba.example.admin.domain.dto.UserDTO;
import sccba.example.admin.domain.query.UserQuery;
import sccba.example.admin.domain.transfer.UserTransfer;
import sccba.example.admin.domain.vo.UserVO;
import sccba.example.admin.service.UserService;
import sccba.example.util.R;

import javax.annotation.Resource;

@Api(tags = "测试")
@RestController
@RequestMapping("/user")
public class UserController {
    @Resource(name = "userService")//根据名称注入
    private UserService userService;


    @ApiOperation("测试swagger3接口")
    @PostMapping("/swagger3")
    public String show2(@ApiParam(value = "用户对象", required = true) @RequestBody UserVO user) {
        return "hello," + user.getName() + ",welcome to springboot swagger3!";
    }

    /**
     *
     * @param userQuery
     * @return
     */
    @ApiOperation("获取用户列表")
    @GetMapping("/list")
    public R getUsers(UserQuery userQuery){
        UserDTO userDTO = userService.getById(userQuery.getUserId());
        return R.ok().putData(UserTransfer.toVO(userDTO));
    }
}

? ? ? ? 定义统一返回类R

package sccba.example.util;

import java.util.HashMap;
import java.util.Map;

public class R extends HashMap<String, Object> {
	private static final long serialVersionUID = 1L;

	public R() {
		put("code", 0);
		put("msg", "操作成功");
	}

	public static R error() {
		return error(1, "操作失败");
	}

	public static R error(String msg) {
		return error(500, msg);
	}

	public static R error(int code, String msg) {
		R r = new R();
		r.put("code", code);
		r.put("msg", msg);
		return r;
	}
	public static R ioterror() {
		R r = new R();
		r.put("errorMsg", "failed");
		r.put("errorCode", "FFFFFFFF");
		return r;
	}
	public static R iotok() {
		R r = new R();
		r.put("errorMsg", "success");
		r.put("errorCode", "00000000 ");
		return r;
	}


	public static R ok(String msg) {
		R r = new R();
		r.put("msg", msg);
		return r;
	}

	public static R ok(Map<String, Object> map) {
		R r = new R();
		r.putAll(map);
		return r;
	}

	public static R ok() {
		return new R();
	}

	@Override
	public R put(String key, Object value) {
		super.put(key, value);
		return this;
	}

	public R putData(Object value) {
		super.put("data", value);
		return this;
	}

}

? ? ? ? ?接口调用效果

六、ideal常用配置及快捷键

1、设置注释格式

2、配置maven

3、安装插件

4、Ctrl相关快捷键

Ctrl + F 在当前文件进行文本查找 (必备)
Ctrl + R 在当前文件进行文本替换 (必备)
Ctrl + Z 撤销 (必备)
Ctrl + Y 删除光标所在行 或 删除选中的行 (必备)
Ctrl + X 剪切光标所在行 或 剪切选择内容
Ctrl + C 复制光标所在行 或 复制选择内容
Ctrl + D 复制光标所在行 或 复制选择内容,并把复制内容插入光标位置下面 (必备)
Ctrl + W 递进式选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展选中范围 (必备)
Ctrl + N 根据输入的 类名 查找类文件
Ctrl + / 注释光标所在行代码,会根据当前不同文件类型使用不同的注释符号 (必备)
Ctrl + End 跳到文件尾
Ctrl + Home 跳到文件头
Ctrl + Space 基础代码补全,默认在 Windows 系统上被输入法占用,需要进行修改,建议修改为 ALT+/(必备)
Ctrl + Tab 编辑窗口切换,如果在切换的过程又加按上delete,则是关闭对应选中的窗口

5、alt相关快捷键

Alt + Enter IntelliJ IDEA 根据光标所在问题,提供快速修复选择,光标放在的位置不同提示的结果也不同 (必备)
Alt + Insert 代码自动生成,如生成对象的 set / get 方法,构造函数,toString() 等(必备)

?6、Shift相关快捷键

Shift + F6 对文件 / 文件夹 重命名
Shift + F7 在 Debug 模式下,智能步入。断点所在行上有多个方法调用,会弹出进入哪个方法

7、Ctrl + Alt相关快捷键

Ctrl + Alt + L 格式化代码,可以对当前文件和整个包目录使用 (必备)
Ctrl + Alt + O 优化导入的类,可以对当前文件和整个包目录使用 (必备)
Ctrl + Alt + 左方向键 退回到上一个操作的地方 (必备)
Ctrl + Alt + 右方向键 前进到上一个操作的地方 (必备)

8、Ctrl + Shift相关快捷键

Ctrl + Shift + F 根据输入内容查找整个项目 或 指定目录内文件 (必备)
Ctrl + Shift + R 根据输入内容替换对应内容,范围为整个项目 或 指定目录内文件 (必备)
Ctrl + Shift + J 自动将下一行合并到当前行末尾 (必备)
Ctrl + Shift + Z 取消撤销 (必备)
Ctrl + Shift + W 递进式取消选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展取消选中范围 (必备)
Ctrl + Shift + N 通过文件名定位 / 打开文件 / 目录,打开目录需要在输入的内容后面多加一个正斜杠 (必备)
Ctrl + Shift + U 对选中的代码进行大 / 小写轮流转换 (必备)
Ctrl + Shift + / 代码块注释 (必备)
Ctrl + Shift + 左键单击 把光标放在某个类变量上,按此快捷键可以直接定位到该类中 (必备)


9、?其他快捷键

F2 跳转到下一个高亮错误 或 警告位置 (必备)
F3 在查找模式下,定位到下一个匹配处
F7 在 Debug 模式下,进入下一步,如果当前行断点是一个方法,则进入当前方法体内,如果该方法体还有方法,则不会进入该内嵌的方法中
F8 在 Debug 模式下,进入下一步,如果当前行断点是一个方法,则不进入当前方法体内
F9 在 Debug 模式下,恢复程序运行,但是如果该断点下面代码还有断点则停在下一个断点上

文章来源:https://blog.csdn.net/C_see/article/details/135595741
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。