SpringBoot导读

SpringBoot

一、导读

1、开发工具及技术栈

  • JDK:jdk1.8.0_191
  • 开发工具:IntelliJIDEA 2020.3.2
  • SpringBoot:
    • 简化Spring的开发
    • 需要一定的java基础
    • 有Spring、SpringMVC、Mybatis框架知识
  • Maven
  • Magic-Api
  • JWT

二、SpringBoot

1、概述

SpringBoot 提供了一种快速使用Spring的方式,基于约定优于配置的思想,可以让开发人员不必在配置和逻辑业务之间进行思维的切换,全身心投入到逻辑业务的代码编写中,从而大打提高开发的效率。一定程度上缩短了开发周期。

2、功能

  1. 自动配置

    SpringBoot是一个运行时的过程,就是程序启动的时候,考虑众多因素,才会决定Spring配置应该用哪个,不该用哪个,该过程时自动的。

  2. 起步依赖

    是一个Maven模型,根据POM定义了其他库的依赖传递,简单说就是把具备某些功能的坐标打包到一起,并提供一些默认的功能。

  3. 辅助功能

    比如嵌入式服务器、安全、指标、健康监测、外部配置等。

  • SpringBoot提供了一种快速开发Spring项目的方式,而不是Spring功能上的增强。

3、快速入门

3.1、pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.4.5</version>
      <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>cn.tjhis</groupId>
  <artifactId>hisApi</artifactId>
  <version>1.0.2</version>
  <name>hisApi</name>
  <description>hisApi</description>
  <properties>
      <java.version>17</java.version>
  </properties>
  <dependencies>
      <!-- 引入magic-api-spring-boot-starter依赖。-->
      <dependency>
          <groupId>org.ssssssss</groupId>
          <artifactId>magic-api-spring-boot-starter</artifactId>
          <version>2.0.2</version>
      </dependency>
      <!-- 定时任务 -->
      <dependency>
          <groupId>org.ssssssss</groupId>
          <artifactId>magic-api-plugin-task</artifactId>
          <version>2.0.2</version>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-jdbc</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <!-- Oracle驱动 -->
      <!--        <dependency>-->
      <!--            <groupId>com.oracle.database.jdbc</groupId>-->
      <!--            <artifactId>ojdbc8</artifactId>-->
      <!--            <scope>runtime</scope>-->
      <!--        </dependency>-->
      <dependency>
          <groupId>com.oracle.database.jdbc</groupId>
          <artifactId>ojdbc6</artifactId>
          <version>11.2.0.4</version>
      </dependency>

      <dependency>
          <groupId>com.oracle.database.nls</groupId>
          <artifactId>orai18n</artifactId>
          <version>19.7.0.0</version>
      </dependency>
      <!-- 日志监控,Druid 用 -->
      <!-- https://mvnrepository.com/artifact/log4j/log4j -->
      <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.17</version>
      </dependency>
      <!-- Druid https://mvnrepository.com/artifact/com.alibaba/druid -->
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid-spring-boot-starter</artifactId>
          <version>1.2.8</version>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
      </dependency>
      <!-- properti.yml的配置文件处理器,写yml文件时会有提示 -->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-configuration-processor</artifactId>
          <optional>true</optional>
      </dependency>
      <!-- Lombok项目是一个java库,它可以自动插入到编辑器和构建工具中,增强java的性能。
           不需要再写getter、setter或equals方法,只要有一个注解,你的类就有一个功能齐全的构建器、自动记录变量等等。 -->
      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
      </dependency>
      <!-- JWT -->
      <dependency>
          <groupId>com.auth0</groupId>
          <artifactId>java-jwt</artifactId>
          <version>3.4.0</version>
      </dependency>
      <!-- hutool -->
      <dependency>
          <groupId>cn.hutool</groupId>
          <artifactId>hutool-all</artifactId>
          <version>5.8.10</version>
      </dependency>
      <!-- bouncycastle SM2 加密 -->
      <dependency>
          <groupId>org.bouncycastle</groupId>
          <artifactId>bcprov-jdk15to18</artifactId>
          <version>1.69</version>
      </dependency>
  </dependencies>
  <build>
      <plugins>
          <plugin>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
      </plugins>
  </build>

</project>

  • 增加启动引导类

    package cn.tjhis.api;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class ApiApplication {
        public static void main(String[] args) {
            SpringApplication.run(ApiApplication.class, args);
        }
    }
    

3.2、配置文件

## 生产环境
server:
  port: 9908
  # 配置静态资源启用 gzip 压缩
  compression:
    enabled: true
    min-response-size: 128
# 配置主数据源
spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
  datasource:
    driver-class-name: oracle.jdbc.OracleDriver #oracle.jdbc.driver.OracleDriver
    username: system
    password: manager
    #url: jdbc:oracle:thin:@192.168.11.10:1521/orcl
    url: jdbc:wrap-jdbc:filters=encoding:jdbc:oracle:thin:@//localhost:1521/orcl
    type: com.alibaba.druid.pool.DruidDataSource
    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置 ,必须导入 druid-spring : 1.1.10 才能配置以下参数
    druid:
      # 处理Oracle的英文字符集乱码的问题,中文字符集屏蔽该行 
      #connection-properties: serverEncoding=ISO-8859-1;clientEncoding=GBK  
      initialSize: 5
      minIdle: 5
      maxActive: 20
      # 配置获取连接等待超时的时间
      maxWait: 60000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      minEvictableIdleTimeMillis: 300000
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      # 打开PSCache,并且指定每个连接上PSCache的大小
      poolPreparedStatements: true
      maxPoolPreparedStatementPerConnectionSize: 20
      # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
      filters: stat,wall,log4j2
      # StatViewServlet配置 sql监控
      stat-view-servlet:
        enabled: true
        url-pattern: "/druid/*"
        reset-enable: false
        login-username: admin
        login-password: Admin@123
        #允许那些ip
        allow: 127.0.0.1,192.168.120.93
        #禁止那些ip
        deny: 192.168.120.93
      # WebStatFilter配置 web-jdbc关联监控
      web-stat-filter:
        enabled: true
        url-pattern: "/*"
        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
      filter:
        stat:
          enabled: true
          merge-sql: true
      #  data:
      # 配置mongo数据源
      #    mongodb:
      #      host: localhost
      #      port: 27017
      #      database: magicapi
      #      username: magicapi
      #      password: 123456
      # 配置redis数据源
    #  redis:
    #    host: localhost
    #    port: 6379
    #    database: 4
    #    timeout: 5000
magic-api:
  web: /magic/web
  security:
    username: admin # 登录用户名
    password: Admin@123 # 登录密码
  resource:
    #    type: database  # 配置接口存储方式,这里选择存在数据库中
    #    table-name: magic_api_file  # 数据库表名
    prefix: /api  # key前缀
    location: d:/magic-api
  # 配置打印SQL
  show-sql: true
  date-pattern: yyyy-MM-dd HH:mm:ss
  page:
    size: size # 页大小的参数名称
    page: page # 页码的参数名称
    default-page: 1 # 未传页码时的默认首页
    default-size: 10 # 未传页大小时的默认页大小
  prefix: api # 接口前缀,可以不配置
  sql-column-case: camel # 启用驼峰命名转换
  backup: #备份相关配置
    enable: false #是否启用
    max-history: -1 #备份保留天数,-1为永久保留
    datasource: magic  #指定数据源(单数据源时无需配置,多数据源时默认使用主数据源,如果存在其他数据源中需要指定。)
    table-name: magic_api_backup #使用数据库存储备份时的表名
  response-code:
    success: 200 #执行成功的code值
    invalid: 400 #参数验证未通过的code值
    exception: 500 #执行出现异常的code值
  response: |- # 配置JSON格式,格式为magic-script中的表达式
    {
      code: code,
      message: message,
      data,
      timestamp,
      requestTime,
      executeTime,
    }
  throw-exception: true
  task:
    thread-name-prefix: magic-task- #线程池名字前缀
    pool:
      size: 8 #线程池大小,默认值为CPU核心数
    shutdown:
      awaitTermination: false #关闭时是否等待任务执行完毕,默认为false
      awaitTerminationPeriod: 10s # 关闭时最多等待任务执行完毕的时间
# 更多配置 https://ssssssss.org/magic-api/config/
person:
  name: 张三
  address:
    - 北京
    - 丰台
    - 富丰桥
  age: 16
  • 创建Controller

  • 小结

    • 在创建项目时,默认使用jar打包方式,因为用main函数启动的。
    • 启动引导类是项目的入口。

4、Magic-api

4.1、简介

  • magic-api 是一个基于Java的接口快速开发框架,编写接口将通过magic-api提供的UI界面完成,自动映射为HTTP接口,无需定义Controller、Service、Dao、Mapper、XML、VO等Java对象即可完成常见的HTTP API接口开发。

  • 之前我们开发一个接口,至少需要Controller,Service,Dao,Mapper文件,还需要各种配置,搭建启动springboot项目,发布完成,接口才能访问,接口才算完成。
    而magic要做的就是通过UI界面动态的配置一下接口路径,出入参,点击保存,接口发布完成,即可访问,不需要编写代码,只需要简单配置,还支持事物,分页,http请求等数据库操作,有点类似于现在的低代码平台

  • 特性

    支持MySQL、MariaDB、Oracle、DB2、PostgreSQL、SQLServer 等支持jdbc规范的数据库
    支持非关系型数据库Redis、Mongodb
    支持集群部署、接口自动同步。
    支持分页查询以及自定义分页查询
    支持多数据源配置,支持在线配置数据源
    支持SQL缓存,以及自定义SQL缓存
    支持自定义JSON结果、自定义分页结果
    支持对接口权限配置、拦截器等功能
    支持运行时动态修改数据源
    支持Swagger接口文档生成
    基于magic-script脚本引擎,动态编译,无需重启,实时发布
    支持Linq式查询,关联、转换更简单
    支持数据库事务、SQL支持拼接,占位符,判断等语法
    支持文件上传、下载、输出图片
    支持脚本历史版本对比与恢复
    支持脚本代码自动提示、参数提示、悬浮提示、错误提示
    支持导入Spring中的Bean、Java中的类
    支持在线调试
    支持自定义工具类、自定义模块包、自定义类型扩展、自定义方言、自定义列名转换等自定义操作

4.2、Magic-api 增删改查

  • Oracle的表名必须用双引号,才能好使
// 新增
return db.table('test_data').insert({ id : 4, name : 'admin'})    
return db.table('test_data').primary('id').save({ id : 4, name : 'admin'})
return db.table(\'user\').insert(body);  
// oracle只有这种方法好使,成功之后返回rowid                
var sql = """ insert into SCOTT.DEPT (DEPTNO,DNAME,LOC) values (#{DEPTNO},#{DNAME},#{LOC})"""
return db.insert(sql,body)
// 表名必须用双引号,才能好使,实际上不是,在这种状态不能开启驼峰sql-column-case ,如果需要驼峰,可以用db.camel()              
return db.table("SCOTT.DEPT").insert(body)                 
                
// 更新
return db.table('test_data').primary('id').update({ id: 4, name : '张三峰'}) 
return db.update(\'update user set userName=\‘李四\’ where id=#{id}\') 
                 
// 删除  
return db.table('test_data').primary('id').where().eq('id',4).delete()
return db.update(\'delete from user where id=#{id}\') 
                 
// 查询单条:路径变量从path对象中获取
return db.table(\'user\')
    .where()
    .eq(\'id\',path.id)
    .selectOne();  
return db.selectValue('select username from user where id = #{id}')   return db.camel().selectOne('select * from user where id = #{id} ')
return db.selectInt('select count(*) from user')     
        
// 查询所有
var sql = """
    select dept_code,dept_name from dept_dict
"""
return db.camel().select(sql)        
return db.camel().select('select * from user')  
return db.camel().table("dept_dict").select()
        
// 分页 ,由于已经在application.yml中配置好了分页参数,可直接使用,下面第7项中有更详细的分页
return db.camel().table(\'user\').page();    
return db.camel().page(sql);   
// 从第11行开始取10行                
return db.camel().table("dept_dict").page(10,11)                
                
// 动态拼接
return db.camel().select("select * from sys_user ?{id,where id = #{id}}");       // 当id有值时,生成SQL:select * from sys_user where id = ?`,   
// 当id无值时,生成SQL:select * from sys_user
return db.select("select * from sys_user ?{id!=null&&id.length() > 3,where id = #{id}}");
// 当id!=null&&id.length() > 3判断为true时,生成SQL:`select * from sys_user where id = ?
// 当判断为false时,生成SQL:select * from sys_user

// 模糊查询                        
return db
    .camel()
    .table("dept_dict")
    .columns('dept_code','dept_name')
    .where()
    .like('dept_code','01%')
    .like('dept_name','%疗区')
    .page()                        

4.3、参数获取

  • ### 这样的`URL`参数`magic-api` 会自动将`name`和`age`映射为同名变量。
    GET http://localhost:9999/xxx/xxx?name=abc&age=49
    
  • Post也会映射为同名参数

  • POST请求:使用body对象可以直接获取请求body中的参数,例如

    {
      "name": "magic-api",
      "version": "9.9.9"
    }
    ## 如要获取name属性 则可通过 body.name 来获取
    
  • Path参数获取:路径变量从path对象中获取,GET请求,请求路径为/detail/

  • 如要获取heade中的 token 可以通过header.token 来获取

4.4、校验

  • assert在 2.0 已经被弃用
//import assert;  //导入断言模块
// 验证不通过时,会终止运行
//assert.notEmpty(body.name,400,'名称不能为空!');
//assert.notEmpty(body.firstLetter,400,'首字母不能为空!');
//return db.table('pms_brand').insert(body);

if (pageSize==null || pageSize==0){
    pageSize=10
}
if (pageIndex==null || pageIndex==0){
    exit 400, '页码不能为空!';
}
// 类型转换
pageSize= pageSize::int
pageIndex= pageIndex::int
var sql = """
    select dept_code,dept_name from dept_dict
"""
return db.page(sql,pageSize,pageSize * (pageIndex - 1))

4.7、切换数据源

// 从数据源key定义为slave的库中查询
return db.slave.select("""
    select * from sys_user
""")

4.8、事物

// 自动事务
var val = db.transaction(()=>{
    var v1 = db.update('...');
    var v2 = db.update('....');
    return v2;
});
return val;

// 手动事务
var tx = db.transaction();  //开启事务
try{
    var value = db.update('...');
    tx.commit();    // 提交事务
    return value;
}catch(e){
    tx.rollback();  // 回滚事务
}

4.9、结果转换

var list = db.table('comm.dept_dict').select();
return list.map((item)=>{
    code : item.deptCode,
    name : item.deptName,
    showStatus : item.clinicAttr==0? '临床' : '其它'
});

4.10、java访问magic

  • 配置文件中的magic的配置不要加prefix,否则在java无总是报找不到路径

  • 建议方法用execute,不要用call

    • execute内部调用接口不包含code以及message信息,同时也不走拦截器。
    • call内部调用接口包含code以及message信息,同时也不走拦截器。
  • 代码

    @RestController
    public class LoginController {
        private final MagicAPIService service;
        private static final Logger logger = LoggerFactory.getLogger(CustomRequestInterceptor.class);
    
        public LoginController(MagicAPIService service) {
            this.service = service;
        }
    
        @GetMapping("/login")
        public Object login(String userName, String password) {
            Map<String, Object> params = new HashMap<>();       
            // 注入变量信息
            params.put("userName", userName);
            // 内部调用接口不包含code以及message信息,同时也不走拦截器。
            Object value = service.call("GET", "/comm/getUserByUserName", params);
            logger.info(value.toString());
            return null;
        }
    }
    

4.11、magic访问java

import cn.tjhis.hisapi.config.JwtConfig;
var jwt = JwtConfig.parse(header.token)
return jwt.payloads.id;

5、properties.yml

  • 优先级:properties.properties > properties.yml > properties.yaml

  • 获取值

    • @Value

      @RestController
      public class TestController {
          @Value("${spring.jackson.date-format}")
          private String dataFormat;
          @GetMapping("/test")
          public String getTest(){
              return "Hello,王红晓," + dataFormat;
          }
      }
      
  • Environment

    @RestController
    public class TestController {
        // 不建议使用Autowired注解,而是用构造的方法注入
        private final Environment env;
        
        public TestController(Environment env) {
            this.env = env;
        }
    
        @GetMapping("/test")
        public String getTest() {
            return "Hello,王红晓," + env.getProperty("spring.jackson.date-format");
        }
    }
    
  • @ConfigurationProperties

    person:
      name: 张三
      age: 18
      address:
        - 北京
        - 丰台
        - 富丰桥
    
// 定义映射的实体类
package cn.tjhis.hisapi.entity;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "person")
@Data
public class Person {
	private String name;
	private int age;
	private String[] address;
}

// 使用
import cn.tjhis.hisapi.entity.Person;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
	private final Environment env;
	private final Person person;
	public TestController(Environment env, Person person) {
		this.env = env;
		this.person = person;
	}

	@GetMapping("/test")
	public String getTest() {
		return "Hello,王红晓," + person;
	}
}

6、profile

  • 激活

    spring:
      profiles:
        active: test
    
  • active对应的配置文件为:application-XXX.yml,其中XXX即可为active的值

  • 文件名

    • application-test.yml:测试环境
    • application-dev.yml:开发环境
    • application-pro.yml:生产环境
  • 虚拟机启动方式:

    • 启动配置里面VM加:-Dspring.profiles.active=pro
  • jar包启动方式

    • 在jar包的cmd命令行输入java -jar ./hisApi-1.0.1.jar --spring.profiles.active=test
    • 直接拷贝个文件和jar包平级application.yml,会优先启用该配置文件,其他配置也会被加载,但是会被当前的文件覆盖,如果放到config文件中,优先级会更高。运行命令:java -jar ./hisApi-1.0.1.jar

7、druid

8、idea快捷键

一、常用快捷键

Ctrl + F12 弹出当前文件结构层(类的方法属性等),可以在弹出的层上直接输入,进行筛选
Ctrl + 左键单击 在打开的文件标题上,弹出该文件路径
Ctrl + N 根据输入的 类名 查找类文件
Ctrl + D 复制光标所在行 或 复制选择内容,并把复制内容插入光标位置下面
Ctrl + P 方法参数提示显示
Ctrl + Alt + O 优化导入的类,可以对当前文件和整个包目录使用
Alt + Insert 代码自动生成,如生成对象的 set / get 方法,构造函数,toString() 等
Shift + F6 对文件 / 文件夹 重命名
Ctrl + Shift + Enter 自动结束代码,行末自动添加分号
Ctrl + B 找变量、方法、类等的来源或者使用过的地方
Ctrl + Alt + B 在某个调用的方法名上使用会跳到具体的实现处,可以跳过接口
Ctrl + Q 光标所在的变量 / 类名 / 方法名等上面(也可以在提示补充的时候按),显示文档内容
Ctrl + Alt + T 对选中的代码弹出环绕选项弹出层(try,if等语句包裹)
Ctrl + Alt + L 格式化代码,可以对当前文件和整个包目录使用
Ctrl + Alt + 左方向键 退回到上一个操作的地方
Ctrl + Alt + 右方向键 前进到上一个操作的地方
Ctrl + Shift + J 自动将下一行合并到当前行末尾
Alt + F8 在 Debug 的状态下,选中对象,弹出可输入计算表达式调试框,查看该输入内容的调试结果
连按两次Shift 弹出 Search Everywhere 弹出层

Alt + F7 查找光标所在的方法 / 变量 / 类被调用的地方
Ctrl + Alt + F7 显示使用的地方。寻找被该类或是变量被调用的地方,用弹出框的方式找出来

Ctrl + F 在当前文件进行文本查找
Ctrl + Shift + F 根据输入内容查找整个项目 或 指定目录内文件

Ctrl + R 在当前文件进行文本替换
Ctrl + Shift + R 根据输入内容替换对应内容,范围为整个项目 或 指定目录内文件

Ctrl + H 显示当前类的层次结构
Ctrl + Alt + H 调用层次
Ctrl + Shift + H 显示方法层次结构

Ctrl + W 递进式选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展选中范围
Ctrl + Shift + W 递进式取消选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展取消选中范围

Ctrl + [ 移动光标到当前所在代码的花括号开始位置
Ctrl + ] 移动光标到当前所在代码的花括号结束位置
Ctrl + Shift + [ 选中从光标所在位置到它的顶部中括号位置
Ctrl + Shift + ] 选中从光标所在位置到它的底部中括号位置

Ctrl + O 选择可重写的方法
Ctrl + I 选择可实现的方法
Ctrl + Y 删除光标所在行 或 删除选中的行
Ctrl + X 剪切光标所在行 或 剪切选择内容
Ctrl + G 在当前文件跳转到指定行处
Ctrl + Q 光标所在的变量 / 类名 / 方法名等上面(也可以在提示补充的时候按),显示文档内容
Ctrl + U 前往当前光标所在的方法的父类的方法 / 接口定义
Ctrl + End 跳到文件尾
Ctrl + Home 跳到文件头

Alt + ` 显示版本控制常用操作菜单弹出层
Alt + Enter 根据光标所在问题,提供快速修复选择,光标放在的位置不同提示的结果也不同

Shift + ESC 隐藏当前 或 最后一个激活的工具窗口
Shift + End 选中光标到当前行尾位置
Shift + Home 选中光标到当前行头位置
Shift + Enter 开始新一行。光标所在行下空出一行,光标定位到新行位置
Shift + 左键单击 在打开的文件名上按此快捷键,可以关闭当前打开文件

Ctrl + Alt + I 光标所在行 或 选中部分进行自动代码缩进,有点类似格式化
Ctrl + Alt + Space 类名自动完成

Ctrl + Shift + N 通过文件名定位 / 打开文件 / 目录,打开目录需要在输入的内容后面多加一个正斜杠
Ctrl + Shift + U 对选中的代码进行大 / 小写轮流转换
Ctrl + Shift + / 代码块注释
Ctrl + Shift + Backspace 退回到上次修改的地方
Ctrl + Shift + F12 编辑器最大化
Ctrl + Shift + 左键单击 把光标放在某个类变量上,按此快捷键可以直接定位到该类中

二、Ctrl相关

Ctrl + F 在当前文件进行文本查找 (必备)
Ctrl + R 在当前文件进行文本替换 (必备)
Ctrl + Z 撤销 (必备)
Ctrl + Y 删除光标所在行 或 删除选中的行 (必备)
Ctrl + X 剪切光标所在行 或 剪切选择内容
Ctrl + C 复制光标所在行 或 复制选择内容
Ctrl + D 复制光标所在行 或 复制选择内容,并把复制内容插入光标位置下面 (必备)
Ctrl + W 递进式选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展选中范围 (必备)
Ctrl + E 显示最近打开的文件记录列表
Ctrl + N 根据输入的 类名 查找类文件
Ctrl + G 在当前文件跳转到指定行处
Ctrl + J 插入自定义动态代码模板
Ctrl + P 方法参数提示显示
Ctrl + Q 光标所在的变量 / 类名 / 方法名等上面(也可以在提示补充的时候按),显示文档内容
Ctrl + U 前往当前光标所在的方法的父类的方法 / 接口定义
Ctrl + B 进入光标所在的方法/变量的接口或是定义处,等效于 Ctrl + 左键单击
Ctrl + K 版本控制提交项目,需要此项目有加入到版本控制才可用
Ctrl + T 版本控制更新项目,需要此项目有加入到版本控制才可用
Ctrl + H 显示当前类的层次结构
Ctrl + O 选择可重写的方法
Ctrl + I 选择可继承的方法
Ctrl + + 展开代码
Ctrl + - 折叠代码
Ctrl + / 注释光标所在行代码,会根据当前不同文件类型使用不同的注释符号 (必备)
Ctrl + [ 移动光标到当前所在代码的花括号开始位置
Ctrl + ] 移动光标到当前所在代码的花括号结束位置
Ctrl + F1 在光标所在的错误代码处显示错误信息
Ctrl + F3 调转到所选中的词的下一个引用位置
Ctrl + F4 关闭当前编辑文件
Ctrl + F8 在 Debug 模式下,设置光标当前行为断点,如果当前已经是断点则去掉断点
Ctrl + F9 执行 Make Project 操作
Ctrl + F11 选中文件 / 文件夹,使用助记符设定 / 取消书签
Ctrl + F12 弹出当前文件结构层,可以在弹出的层上直接输入,进行筛选
Ctrl + Tab 编辑窗口切换,如果在切换的过程又加按上delete,则是关闭对应选中的窗口
Ctrl + Enter 智能分隔行
Ctrl + End 跳到文件尾
Ctrl + Home 跳到文件头
Ctrl + Space 基础代码补全,默认在 Windows 系统上被输入法占用,需要进行修改,建议修改为 ALT+/(必备)
Ctrl + Delete 删除光标后面的单词或是中文句
Ctrl + BackSpace 删除光标前面的单词或是中文句
Ctrl + 1,2,3...9 定位到对应数值的书签位置
Ctrl + 左键单击 在打开的文件标题上,弹出该文件路径
Ctrl + 光标定位 按 Ctrl 不要松开,会显示光标所在的类信息摘要
Ctrl + 左方向键 光标跳转到当前单词 / 中文句的左侧开头位置
Ctrl + 右方向键 光标跳转到当前单词 / 中文句的右侧开头位置
Ctrl + 前方向键 等效于鼠标滚轮向前效果
Ctrl + 后方向键 等效于鼠标滚轮向后效果

三、Alt相关

Alt + ` 显示版本控制常用操作菜单弹出层
Alt + Q 弹出一个提示,显示当前类的声明 / 上下文信息
Alt + F1 显示当前文件选择目标弹出层,弹出层中有很多目标可以进行选择
Alt + F2 对于前面页面,显示各类浏览器打开目标选择弹出层
Alt + F3 选中文本,逐个往下查找相同文本,并高亮显示
Alt + F7 查找光标所在的方法 / 变量 / 类被调用的地方
Alt + F8 在 Debug 的状态下,选中对象,弹出可输入计算表达式调试框,查看该输入内容的调试结果
Alt + Home 定位 / 显示到当前文件的 Navigation Bar
Alt + Enter IntelliJ IDEA 根据光标所在问题,提供快速修复选择,光标放在的位置不同提示的结果也不同 (必备)
Alt + Insert 代码自动生成,如生成对象的 set / get 方法,构造函数,toString() 等(必备)
Alt + 左方向键 按左方向切换当前已打开的文件视图
Alt + 右方向键 按右方向切换当前已打开的文件视图
Alt + 前方向键 当前光标跳转到当前文件的前一个方法名位置
Alt + 后方向键 当前光标跳转到当前文件的后一个方法名位置
Alt + 1,2,3...9 显示对应数值的选项卡,其中 1 是 Project 用得最多

四、Shift相关

Shift + F1 如果有外部文档可以连接外部文档
Shift + F2 跳转到上一个高亮错误 或 警告位置
Shift + F3 在查找模式下,查找匹配上一个
Shift + F4 对当前打开的文件,使用新Windows窗口打开,旧窗口保留
Shift + F6 对文件 / 文件夹 重命名
Shift + F7 在 Debug 模式下,智能步入。断点所在行上有多个方法调用,会弹出进入哪个方法
Shift + F8 在 Debug 模式下,跳出,表现出来的效果跟 F9 一样
Shift + F9 等效于点击工具栏的 Debug 按钮
Shift + F10 等效于点击工具栏的 Run 按钮
Shift + F11 弹出书签显示层
Shift + Tab 取消缩进
Shift + ESC 隐藏当前 或 最后一个激活的工具窗口
Shift + End 选中光标到当前行尾位置
Shift + Home 选中光标到当前行头位置
Shift + Enter 开始新一行。光标所在行下空出一行,光标定位到新行位置
Shift + 左键单击 在打开的文件名上按此快捷键,可以关闭当前打开文件
Shift + 滚轮前后滚动 当前文件的横向滚动轴滚动

五、Ctrl + Alt相关

Ctrl + Alt + L 格式化代码,可以对当前文件和整个包目录使用 (必备)

Ctrl + Alt + M 提取方法:选中代码,快速抽取为方法 (必备)

Ctrl + Alt + O 优化导入的类,可以对当前文件和整个包目录使用 (必备)
Ctrl + Alt + I 光标所在行 或 选中部分进行自动代码缩进,有点类似格式化
Ctrl + Alt + T 对选中的代码弹出环绕选项弹出层
Ctrl + Alt + J 弹出模板选择窗口,将选定的代码加入动态模板中
Ctrl + Alt + H 调用层次
Ctrl + Alt + B 在某个调用的方法名上使用会跳到具体的实现处,可以跳过接口
Ctrl + Alt + V 快速引进变量
Ctrl + Alt + Y 同步、刷新
Ctrl + Alt + S 打开 IntelliJ IDEA 系统设置
Ctrl + Alt + F7 显示使用的地方。寻找被该类或是变量被调用的地方,用弹出框的方式找出来
Ctrl + Alt + F11 切换全屏模式
Ctrl + Alt + Enter 光标所在行上空出一行,光标定位到新行
Ctrl + Alt + Home 弹出跟当前文件有关联的文件弹出层
Ctrl + Alt + Space 类名自动完成
Ctrl + Alt + 左方向键 退回到上一个操作的地方 (必备)
Ctrl + Alt + 右方向键 前进到上一个操作的地方 (必备)
Ctrl + Alt + 前方向键 在查找模式下,跳到上个查找的文件
Ctrl + Alt + 后方向键 在查找模式下,跳到下个查找的文件

六、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 + T 对当前类生成单元测试类,如果已经存在的单元测试类则可以进行选择
Ctrl + Shift + C 复制当前文件磁盘路径到剪贴板
Ctrl + Shift + V 弹出缓存的最近拷贝的内容管理器弹出层
Ctrl + Shift + E 显示最近修改的文件列表的弹出层
Ctrl + Shift + H 显示方法层次结构
Ctrl + Shift + B 跳转到类型声明处
Ctrl + Shift + I 快速查看光标所在的方法 或 类的定义
Ctrl + Shift + A 查找动作 / 设置
Ctrl + Shift + / 代码块注释 (必备)
Ctrl + Shift + [ 选中从光标所在位置到它的顶部中括号位置
Ctrl + Shift + ] 选中从光标所在位置到它的底部中括号位置
Ctrl + Shift + + 展开所有代码
Ctrl + Shift + - 折叠所有代码
Ctrl + Shift + F7 高亮显示所有该选中文本,按Esc高亮消失
Ctrl + Shift + F8 在 Debug 模式下,指定断点进入条件
Ctrl + Shift + F9 编译选中的文件 / 包 / Module
Ctrl + Shift + F12 编辑器最大化
Ctrl + Shift + Space 智能代码提示
Ctrl + Shift + Enter 自动结束代码,行末自动添加分号 (必备)
Ctrl + Shift + Backspace 退回到上次修改的地方
Ctrl + Shift + 1,2,3...9 快速添加指定数值的书签
Ctrl + Shift + 左键单击 把光标放在某个类变量上,按此快捷键可以直接定位到该类中 (必备)
Ctrl + Shift + 左方向键 在代码文件上,光标跳转到当前单词 / 中文句的左侧开头位置,同时选中该单词 / 中文句
Ctrl + Shift + 右方向键 在代码文件上,光标跳转到当前单词 / 中文句的右侧开头位置,同时选中该单词 / 中文句
Ctrl + Shift + 左方向键 在光标焦点是在工具选项卡上,缩小选项卡区域
Ctrl + Shift + 右方向键 在光标焦点是在工具选项卡上,扩大选项卡区域
Ctrl + Shift + 前方向键 光标放在方法名上,将方法移动到上一个方法前面,调整方法排序
Ctrl + Shift + 后方向键 光标放在方法名上,将方法移动到下一个方法前面,调整方法排序

七、Alt + Shift相关

Alt + Shift + N 选择 / 添加 task
Alt + Shift + F 显示添加到收藏夹弹出层 / 添加到收藏夹
Alt + Shift + C 查看最近操作项目的变化情况列表
Alt + Shift + I 查看项目当前文件
Alt + Shift + F7 在 Debug 模式下,下一步,进入当前方法体内,如果方法体还有方法,则会进入该内嵌的方法中,依此循环进入
Alt + Shift + F9 弹出 Debug 的可选择菜单
Alt + Shift + F10 弹出 Run 的可选择菜单
Alt + Shift + 左键双击 选择被双击的单词 / 中文句,按住不放,可以同时选择其他单词 / 中文句
Alt + Shift + 前方向键 移动光标所在行向上移动
Alt + Shift + 后方向键 移动光标所在行向下移动

八、其他

F2 跳转到下一个高亮错误 或 警告位置 (必备)
F3 在查找模式下,定位到下一个匹配处
F4 编辑源
F7 在 Debug 模式下,进入下一步,如果当前行断点是一个方法,则进入当前方法体内,如果该方法体还有方法,则不会进入该内嵌的方法中
F8 在 Debug 模式下,进入下一步,如果当前行断点是一个方法,则不进入当前方法体内
F9 在 Debug 模式下,恢复程序运行,但是如果该断点下面代码还有断点则停在下一个断点上
F11 添加书签
F12 回到前一个工具窗口
Tab 缩进
ESC 从工具窗口进入代码文件窗口

Ctrl + Shift + Alt + V 无格式黏贴
Ctrl + Shift + Alt + N 前往指定的变量 / 方法
Ctrl + Shift + Alt + S 打开当前项目设置
Ctrl + Shift + Alt + C 复制参考信息

9、idea其他操作技巧

  • 输入sout:会输出System.out.prinln()
  • 输入main:会输出public static void main(String[] args) {}
  • 输入4.fori:会输出for (int i = 0; i < 4; i++) {}
  • 输入arr.length.fori:会输出for (int i = 0; i < arr.length; i++) {}

10、推荐插件

  • Chinese (Simplified) Language Pack
  • Alibaba Java Coding Guidelines阿里巴巴代码规范检查插件
  • Presentation Assistant 快捷键展示 Key Promoter X 快捷键提示插件 弃用,前一个好用
  • Gsonformat
  • Translation翻译插件
  • One Dark Theme
  • Rainbow Brackets彩虹括号插件
  • Codota
  • MybatisX 高效操作Mybatis plus插件
  • PTG 自动生成JavaBean
  • HighlightBracketPair —— 括号开始结尾 高亮显示。
  • Grep Console 控制台日志 高亮
  • google-java-format —— 代码自动格式化
  • Leetcode Editor 可以在IDEA中在线刷题。
  • Material Theme UI ——IDEA主题插件
  • RoboPOJOGenerator—JSON(根据json生成类)(GsonFormat也可以,但是好久没更新过了)
  • Atom Material File Icons

三、融合其他框架

1、jwt

1.1、加入依赖

<!-- JWT -->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.4.0</version>
</dependency>

1.2、配置

config:
  jwt:
    # 是否校验 1 开 ; 0 关
    isOpen: 1
    # 加密密钥
    secret: 92df4304-80c6-43b6-9bb2-beb6cf9b6845
    # token有效时长
    expire: 3600
    # header 名称
    header: token

1.3、配置类

package cn.tjhis.hisapi.config;

import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.signers.JWTSignerUtil;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import cn.hutool.jwt.JWTUtil;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;

/**
 * 描述:JWT的token,区分大小写
 * 路径:cn.tjhis.hisapi.config
 * 工程:hisApi
 * 作者:wanghx
 * 日期:2023-02-06 10:24
 */
@ConfigurationProperties(prefix = "config.jwt") // 用于绑定属性,其中prefix表示所绑定的属性的前缀。
@Component  // 表示将该类标识为Bean
@Data
public class JwtConfig {

    private int isOpen;
    private String secret;
    private long expire;
    private String header;


    /**
     * 生成token
     * @param payload
     * @return
     */
    public String createToken (Map<String,Object> payload){
        Date nowDate = new Date();
        Date expireDate = new Date(nowDate.getTime() + expire * 1000);//过期时间
        //签发时间
        payload.put(JWTPayload.ISSUED_AT, nowDate);
        //生效时间
        payload.put(JWTPayload.NOT_BEFORE, nowDate);
        //过期时间 最大有效期1天强制过期
        payload.put(JWTPayload.EXPIRES_AT, expireDate);
        return JWTUtil.createToken(payload, JWTSignerUtil.hs256(secret.getBytes(StandardCharsets.UTF_8)));
    }
    /**
     * 解析token
     * @param token
     * @return
     */
    public JWT parse(String token){
        return JWT.create().setSigner(JWTSignerUtil.hs256(secret.getBytes(StandardCharsets.UTF_8))).parse(token);
    }
}

1.4、编写controller层下UserController

package cn.tjhis.hisapi.controller;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import cn.tjhis.hisapi.config.JwtConfig;
import cn.tjhis.hisapi.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.ssssssss.magicapi.core.model.JsonBean;
import org.ssssssss.magicapi.core.service.MagicAPIService;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 描述:登录
 * 路径:cn.tjhis.hisapi.controller
 * 工程:hisApi
 * 作者:wanghx
 * 日期:2023-02-06 06:07
 */
@RestController
public class LoginController {
    private final MagicAPIService service;
    private static final Logger logger = LoggerFactory.getLogger(LoginController.class);
    @Resource
    private JwtConfig jwtConfig ;
    public LoginController(MagicAPIService service) {
        this.service = service;
    }

    @GetMapping("/login")
    public Object login(String userName, String password) {
        if (StrUtil.isEmpty(userName)){
            return new JsonBean<>(-1, "用户名不能为空!");
        }
        if (StrUtil.isEmpty(password)){
            return new JsonBean<>(-1, "密码不能为空!");
        }
        // 根据用户名获取信息
        Map<String, Object> params = new HashMap<>();
        // 注入变量信息
        params.put("userName", userName.toUpperCase());
        // 内部调用接口不包含code以及message信息,同时也不走拦截器。
        try {
            LinkedHashMap linkedHashMap = service.execute("GET", "/comm/getUserByUserName", params);
            if (linkedHashMap == null){
                return new JsonBean<>(-1, "用户不存在!");
            }
            // 将obj转换成User对象
            User user = JSONUtil.toBean(JSONUtil.parseObj(linkedHashMap),User.class);
            //获取密文字节数组
            String pwd = (user.getUserPwd() + "wanghx").toUpperCase();
            // 字符串反转后md5加密
            String pwdEnc = SecureUtil.md5(StrUtil.reverse(pwd));
            if (password.equals(pwdEnc))
            {
                // token中不携带密码
                linkedHashMap.remove("userPwd");
                String token = jwtConfig.createToken(linkedHashMap);
                return new JsonBean<>(200,"success",token);
            }
            else
            {
                return new JsonBean<>(-1, "密码不正确!");
            }
        }
        catch (Exception e){
            return new JsonBean<>(-1, e.getMessage());
        }

    }
}

1.5、拦截器

package cn.tjhis.hisapi.interceptor;

import cn.hutool.jwt.JWT;
import cn.tjhis.hisapi.config.JwtConfig;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.ssssssss.magicapi.core.interceptor.RequestInterceptor;
import org.ssssssss.magicapi.core.model.ApiInfo;
import org.ssssssss.magicapi.core.model.JsonBean;
import org.ssssssss.magicapi.core.model.Options;
import org.ssssssss.script.MagicScriptContext;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 自定义请求拦截器,可实现鉴权
 * https://ssssssss.org/magic-api/pages/senior/interceptor/
 *
 * @see RequestInterceptor
 */
@Component
@Order(1) //拦截器顺序,可选
public class CustomRequestInterceptor implements RequestInterceptor {
    @Resource
    private JwtConfig jwtConfig;
    private static final Logger logger = LoggerFactory.getLogger(CustomRequestInterceptor.class);

    /**
     * 接口请求之前
     *
     * @param info    接口信息
     * @param context 脚本变量信息
     */
    @Override
    public Object preHandle(ApiInfo info, MagicScriptContext context, HttpServletRequest request, HttpServletResponse response) throws Exception {
        String path = request.getRequestURI();
        logger.info("请求接口:{},{}", info.getName(), Options.REQUIRE_LOGIN);
        // 是否开启
        if (jwtConfig.getIsOpen()==1){
            //获取请求头中的令牌
            String token = request.getHeader(jwtConfig.getHeader());

            try {
                //验证令牌
                JWT verify = jwtConfig.parse(token);
                return null;
            } catch (SignatureVerificationException e) {
                return new JsonBean<>(-1,"无效签名");
            } catch (TokenExpiredException e) {
                return new JsonBean<>(-1,"token过期");
            } catch (AlgorithmMismatchException e) {
                return new JsonBean<>(-1,"token算法不一致");
            } catch (Exception e) {
                return new JsonBean<>(-1,"token无效");
            }
        }
        return null;
    }

    /**
     * 接口执行之后
     *
     * @param info    接口信息
     * @param context 变量信息
     * @param value   即将要返回到页面的值
     */
    @Override
    public Object postHandle(ApiInfo info, MagicScriptContext context, Object value, HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.info("{} 执行完毕,返回结果:{}", info.getName(), value);
        return null;
    }
}

1.6、magic-api中使用token

import cn.tjhis.hisapi.config.JwtConfig;
var jwt = JwtConfig.parse(header.token)
return jwt.payloads.id;

2、Redis

2.1、引入依赖

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

2.2、注入后编写代码

  • 注入的时候用Resource注解或者构造器,不推荐用 Autowired
  • redisTemplate 这个名字不能写错,否则报错:expected single matching bean but found 2: redisTemplate,stringRedisTemplate
  • @Resource注解是javax包中的注解,它是优先byName来装配的,如果byName无法装配,则会自动尝试byType装配,在byType装配时,要求匹配类型的对象必须有且仅有1个,如果无法装配,则会报告错误@Autowired注解是Spring框架中的注解,它是优先byType来装配的,
  • @Autowired为Spring提供的注解,需要导入包:org.springframework.beans.factory.annotation.Autowired
  • @Resource注解由J2EE提供,需要导入包:javax.annotation.Resource
package cn.tjhis.springredis.controller;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * 描述:
 * 路径:cn.tjhis.springredis.controller
 * 工程:spring-redis
 * 作者:wanghx
 * 日期:2023-02-07 06:15
 */
@RestController
public class TestController {
    @Resource
    private RedisTemplate redisTemplate;
    @GetMapping("get")
    public Object get(String key){
        return redisTemplate.boundValueOps(key).get();
    }
    @GetMapping("set")
    public void set(String key,String name){
        redisTemplate.boundValueOps(key).set(name);
    }
}

3、logback

  • 基本信息(不用添加任何pom引用)

    • SpringBoot版本2.4.5
    • 日志框架SLF4J
    • 日志框架的实现LockBack
  • 使用xml配置可以完成yml配置实现不了的功能,比如按天将日志归档。

  • xml有多种命名形式,但官方推荐的命名是logback-spring.xml

  • 日志文件输出在项目根目录下的logs文件夹下。

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration scan="true" scanPeriod="60 seconds" debug="false">
        <contextName>logback</contextName>
        <!--控制台输出内容的颜色转换以及格式-->
        <substitutionProperty name="logging.pattern.console"
                              value="%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
        <!--日志文件输出内容的格式-->
        <substitutionProperty name="logging.pattern.file"
                              value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
        <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
        <conversionRule conversionWord="wex"
                        converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
        <conversionRule conversionWord="wEx"
                        converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
        <!--输出到控制台-->
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
            <!--控制台使用layout节点-->
            <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>
                    ${logging.pattern.console}
                </pattern>
            </layout>
        </appender>
        <!--按天生成日志-->
        <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <Prudent>true</Prudent>
            <!--滚动策略,我配置了按天生成日志文件-->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--相对路径,生成的文件就在项目根目录下-->
                <FileNamePattern>
                    logs/%d{yyyy-MM-dd}.log
                </FileNamePattern>
                <!--注意超过365天的日志文件会被删除,即使已经按天分开也会删除-->
                <MaxHistory>365</MaxHistory>
            </rollingPolicy>
            <!--日志文件里只保存ERROR及以上级别的日志 INFO  -->
    <!--        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">-->
    <!--            <level>INFO</level>-->
    <!--        </filter>-->
            <!--文件使用encoder节点-->
            <encoder>
                <Pattern>
                    ${logging.pattern.file}
                </Pattern>
            </encoder>
        </appender>
        <!--这个logger里的配置相当于之前yml里的logging.level.com.lpc: trace-->
        <!--additivity的作用-->
        <!--true,则子Logger不止会在自己的appender里输出,还会在root的logger的appender里输出-->
        <!--而这个logger里没配置appender,所以得交给root打印-->
        <!--所以cn.tjhis.hisapi包里的日志从TRACE级别开始-->
        <!--其他包里的日志根据root的配置从INFO级别开始打印-->
        <logger name="cn.tjhis.hisapi" level="TRACE" additivity="true">
        </logger>
        <root level="INFO">
            <appender-ref ref="console"/>
            <appender-ref ref="file"/>
        </root>
    </configuration>
    

4、hutool

4.1、db

  • Maven项目中在src/main/resources目录下添加db.setting文件(非Maven项目添加到ClassPath中即可),[mysql]是分组,如果只连接一个数据库,可不写,如果写了,必须显式的指定,否则报错No config for group: []

    ## db.setting文件
    [mysql]
    url = jdbc:mysql://localhost:3306/net6Api
    user = admin
    pass = Admin@123
    
    ## 可选配置
    # 是否在日志中显示执行的SQL
    showSql = true
    # 是否格式化显示的SQL
    formatSql = false
    # 是否显示SQL参数
    showParams = true
    # 打印SQL的日志等级,默认debug,可以是info、warn、error
    sqlLevel = debug
    
  • 添加依赖

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <mysql.version>8.0.27</mysql.version>
        <hutool.version>5.8.12</hutool.version>
    </properties>
    <dependencies>
        <!--mysql数据库驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!-- 引入 hutool -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>
    </dependencies>
    
  • 测试

    import java.sql.SQLException;
    import java.util.List;
    
    /**
     * 描述:hutool的DB测试类
     * 路径:cn.tjhis.hutool
     * 工程:testHutool
     * 作者:wanghx
     * 日期:2023-02-11 07:50
     */
    public class DbTest {
        public static void main(String[] args) {
            // 只有一个数据库,可不写,[mysql]
            Db db = Db.use("mysql");
            try {
                //  查询全部
                List<Entity> payrollInfo = db.findAll("payroll_info");
                Console.log(payrollInfo.get(0).getStr("employee_name"));
                // 条件查询
                List<Entity> list = db.findAll(Entity.create("payroll_info").set("id", 5));
                JSON json = JSONUtil.parse(list);
                Console.error(json.getByPath("salary_month"));
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
    
    

5、mybatis

  • 搭建工程

  • 引入依赖

    • 注意spring-boot-starter版本2.4.5mybatis-spring-boot-starter的版本2.2.2
    • 也不需要加@Component或者@Repository或者@MapperScan等等
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.2</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.8</version>
    </dependency>
    <dependency>
        <groupId>com.oracle.database.jdbc</groupId>
        <artifactId>ojdbc6</artifactId>
        <version>11.2.0.4</version>
    </dependency>
    
    <dependency>
        <groupId>com.oracle.database.nls</groupId>
        <artifactId>orai18n</artifactId>
        <version>19.7.0.0</version>
    </dependency>
    
  • 编写DataSource和mybatis相关配置proterties.yml

  • 定义表和实体类

    @Data
    public class Dept {
        private int deptNo;
        private String dName;
        private String loc;
    }
    
  • 编写dao和mapper

    @Mapper
    public interface DeptMapper {
        /**
         * 查询所有科室
         * @return 返回所有科室
         */
        @Select("select deptno, dname, loc  from scott.dept")
        public List<Dept> findDeptList();
    }
    
  • 编写controller

    @RestController
    public class DeptController {
        @Resource
        private DeptMapper mapper;
        @GetMapping("getDeptAll")
        public String getDeptList(){
            JSON json = JSONUtil.parse(mapper.findDeptList());
            return json.toString();
        }
    }
    
  • 测试

    @SpringBootTest
    class SpringbootMybatisApplicationTests {
    
        @Resource
        private DeptMapper mapper;
        @Test
        void test() {
            List<Dept> deptList = mapper.findDeptList();
            String json = JSONUtil.parse(deptList).toString();
            System.out.println(json);
        }
    
    }
    

6、Mybatis Plus(简称 MP)

  • 优势:

    • 是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
    • 内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
    • 只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 依赖

    <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.2</version>
    </dependency>
    
    
  • 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹:

    @SpringBootApplication
    @MapperScan("cn.tjhis.springboot.mybatis.plus.mapper")
    public class SpringbootMybatisPlusApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringbootMybatisPlusApplication.class, args);
        }
    
    }
    
  • 创建实体

    • 默认生成的语句是:SELECT dept_no,d_name,loc FROM scott.dept,所以需要指定表名和映射的字段名。
    • 需要指出表名:@TableName
    • 需要指定字段:@TableField
    @Data
    @TableName("scott.dept")
    public class Dept {
        @TableField("deptno")
        private int deptNo;
        @TableField("dname")
        private String dName;
        private String loc;
    }
    
  • 创建mapper

    • 不需要写@Mapper注解
    • DeptMapper中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件
    public interface DeptMapper extends BaseMapper<Dept> {
    }
    
  • 测试

    @SpringBootTest
    class SpringbootMybatisPlusApplicationTests {
        @Resource
        private DeptMapper deptMapper;
    
        @Test
        void test() {
            System.out.println(("----- selectAll method test ------"));
            List<Dept> userList = deptMapper.selectList(null);
            userList.forEach(System.out::println);
        }
    }
    
posted @ 2023-02-20 17:21  his365  阅读(79)  评论(0编辑  收藏  举报