跳至主要內容

项目总览

Yang大约 10 分钟

IDEA

快捷键

  • Ctrl + D:快速复制当前行
  • Alt + Shift + 上下箭头:快速向上或向下移动当前行
  • Home:光标跳到行首
  • End:光标跳到行尾
  • Alt + Enter:万能快捷键
  • Shift + Shift:查找所有
  • Cmd + O:查找类
  • Cmd + Shift + O:查找文件
  • Cmd + Shift + A:查找操作
  • Shift + F6:重构 - 重命名
  • Cmd + Alt + V:自动生成返回值
  • Cmd + E:打开最近的文件
  • Cmd + K:提交变更

插件

Maven Helper

解决依赖冲突问题

Free Mybatis plugin

一款增强 idea 对 mybatis 支持的插件

  • 生成 mapper xml 文件
  • 快速从代码跳转到 mapper 及从 mapper 返回代码
  • mybatis 自动补全及语法错误提示
  • 集成 mybatis generator gui 界面
  • 根据数据库注解,生成 swagger model 注解

Git

  • 红色:还没交给 Git 管理
  • 绿色:Git 已管理,还未提交
  • 蓝色:作过修改,还未提交
  • 灰色:文件删除,还未提交

技术选型

Spring Boot

版本:2.2.1.RELEASE

版本

  • CURRENT:最新的 GA 版本
  • GA:General Availability,发布版本,面向大众的功能完整的可用稳定版本
  • SNAPSHOT:(尽量不要使用)快照,随时可能被修改的版本

2.0 版本升级内容

环境升级
  • Java 8 +
  • Tomcat 8 +
  • Thymeleaf 3 :用来开发 Web 和独立环境项目的服务器端的 Java 模版引擎
  • HIBERNATE 5.2:ORM 框架,全称为 Object_Relative DateBase-Mapping,在 Java 对象与关系数据库之间建立某种映射,以实现直接存取 Java 对象
默认软件优化
  • Spring Security:安全框架
新的功能
  • HTTP2 的支持

MySQL

版本:8.0.x

MyBatis

版本:3.4.6

集成配置

添加依赖
<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>1.3.2</version>
</dependency>
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
</dependency>
添加数据源
spring.datasource.url=jdbc:mysql://localhost:3306/wiki?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&autoReconnect=true
spring.datasource.username=wiki
spring.datasource.password=11160328
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
添加配置
mybatis.mapper-locations=classpath:/mapper/**/*.xml

自动生成插件

添加依赖
<!-- pom.xml -->
<plugin>
  <groupId>org.mybatis.generator</groupId>
  <artifactId>mybatis-generator-maven-plugin</artifactId>
  <version>1.3.7</version>
  <configuration>
    <!--
		设置配置文件路径,默认为 resouces
		<configurationFile>src/main/resources/generator/generator-config.xml</configurationFile>
		-->

    <!--是否覆盖原有文件-->
    <overwrite>true</overwrite>
    <verbose>true</verbose>
  </configuration>
</plugin>
添加配置文件
<!-- generator-config.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
  <!-- 配置文件,放在resource目录下即可 -->
  <!--数据库驱动个人配置-->
  <classPathEntry
    location="/Library/MavenRepo/mysql/mysql-connector-java/8.0.18/mysql-connector-java-8.0.18.jar"/>
  <context id="MysqlTables" targetRuntime="MyBatis3">
    <property name="autoDelimitKeywords" value="true"/>
    <!--可以使用``包括字段名,避免字段名与sql保留字冲突报错-->
    <property name="beginningDelimiter" value="`"/>
    <property name="endingDelimiter" value="`"/>
    <!-- optional,旨在创建class时,对注释进行控制 -->
    <commentGenerator>
      <property name="suppressDate" value="true"/>
      <property name="suppressAllComments" value="true"/>
    </commentGenerator>
    <!--数据库链接地址账号密码-->
    <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
      connectionURL="jdbc:mysql://127.0.0.1:3306/imooc_mall?useUnicode=true&amp;characterEncoding=UTF-8&amp;zeroDateTimeBehavior=convertToNull"
      userId="root"
      password="11160328">
      <property name="nullCatalogMeansCurrent" value="true"/>
    </jdbcConnection>
    <!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制-->
    <javaTypeResolver>
      <property name="forceBigDecimals" value="false"/>
    </javaTypeResolver>
    <!--生成Model类存放位置-->
    <javaModelGenerator targetPackage="com.imooc.mall.model.pojo"
      targetProject="src/main/java">
      <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
      <property name="enableSubPackages" value="true"/>
      <!-- 是否对类CHAR类型的列的数据进行trim操作 -->
      <property name="trimStrings" value="true"/>
      <!-- 建立的Model对象是否 不可改变  即生成的Model对象不会有 setter方法,只有构造方法 -->
      <property name="immutable" value="false"/>
    </javaModelGenerator>
    <!--生成mapper映射文件存放位置-->
    <sqlMapGenerator targetPackage="mappers" targetProject="src/main/resources">
      <property name="enableSubPackages" value="true"/>
    </sqlMapGenerator>
    <!--生成Dao类存放位置-->
    <javaClientGenerator type="XMLMAPPER" targetPackage="com.imooc.mall.model.dao"
      targetProject="src/main/java">
      <property name="enableSubPackages" value="true"/>
    </javaClientGenerator>
    <!--生成对应表及类名-->
    <table schema="root" tableName="imooc_mall_cart" domainObjectName="Cart"
      enableCountByExample="false"
      enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
      selectByExampleQueryId="false">
    </table>
    <table tableName="imooc_mall_category" domainObjectName="Category" enableCountByExample="false"
      enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
      selectByExampleQueryId="false">
    </table>
    <table tableName="imooc_mall_order" domainObjectName="Order" enableCountByExample="false"
      enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
      selectByExampleQueryId="false">
    </table>
    <table tableName="imooc_mall_order_item" domainObjectName="OrderItem"
      enableCountByExample="false"
      enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
      selectByExampleQueryId="false">
    </table>
    <table tableName="imooc_mall_product" domainObjectName="Product" enableCountByExample="false"
      enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
      selectByExampleQueryId="false">
    </table>
    <table tableName="imooc_mall_user" domainObjectName="User" enableCountByExample="false"
      enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
      selectByExampleQueryId="false">
    </table>

  </context>
</generatorConfiguration>
使用
  • 依次点击:Maven 面板 - 插件 - mybatis-generator - mybatis-generator:generator(双击)

Maven

版本:3.6.1

log4j2

版本:2.12.1

  • tail -f [文件路径]:实时监控文件变化

日志级别

  • error:错误
  • warn:警告
  • info:信息(请求,等等)
  • debug:调试(开发者输出信息,等等)
  • trace:更详细的信息,一般框架开发者才会关注到

排除 Logback 依赖

不同的日志组件在一起会有冲突,所以需要排除后才能使用更好用的日志组件

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <!--排除 Logback-->
    <exclusions>
      <exclusion>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-logging</artifactId>
      </exclusion>
    </exclusions>
  </dependency>

使用

添加依赖

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

添加配置文件

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="fatal">
  <Properties>
    <Property name="baseDir" value="${sys:user.home}/logs"/>
  </Properties>

  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
      <ThresholdFilter level="info" onMatch="ACCEPT"
        onMismatch="DENY"/>
      <PatternLayout
        pattern="[%d{MM:dd HH:mm:ss.SSS}] [%level] [%logger{36}] - %msg%n"/>
    </Console>

    <!--debug级别日志文件输出-->
    <RollingFile name="debug_appender" fileName="${baseDir}/debug.log"
      filePattern="${baseDir}/debug_%i.log.%d{yyyy-MM-dd}">
      <!-- 过滤器 -->
      <Filters>
        <!-- 限制日志级别在debug及以上在info以下 -->
        <ThresholdFilter level="debug"/>
        <ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL"/>
      </Filters>
      <!-- 日志格式 -->
      <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
      <!-- 策略 -->
      <Policies>
        <!-- 每隔一天转存 -->
        <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
        <!-- 文件大小 -->
        <SizeBasedTriggeringPolicy size="100 MB"/>
      </Policies>
    </RollingFile>

    <!-- info级别日志文件输出 -->
    <RollingFile name="info_appender" fileName="${baseDir}/info.log"
      filePattern="${baseDir}/info_%i.log.%d{yyyy-MM-dd}">
      <!-- 过滤器 -->
      <Filters>
        <!-- 限制日志级别在info及以上在error以下 -->
        <ThresholdFilter level="info"/>
        <ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>
      </Filters>
      <!-- 日志格式 -->
      <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
      <!-- 策略 -->
      <Policies>
        <!-- 每隔一天转存 -->
        <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
        <!-- 文件大小 -->
        <SizeBasedTriggeringPolicy size="100 MB"/>
      </Policies>
    </RollingFile>

    <!-- error级别日志文件输出 -->
    <RollingFile name="error_appender" fileName="${baseDir}/error.log"
      filePattern="${baseDir}/error_%i.log.%d{yyyy-MM-dd}">
      <!-- 过滤器 -->
      <Filters>
        <!-- 限制日志级别在error及以上 -->
        <ThresholdFilter level="error"/>
      </Filters>
      <!-- 日志格式 -->
      <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
      <Policies>
        <!-- 每隔一天转存 -->
        <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
        <!-- 文件大小 -->
        <SizeBasedTriggeringPolicy size="100 MB"/>
      </Policies>
    </RollingFile>
  </Appenders>
  <Loggers>
    <Root level="debug">
      <AppenderRef ref="Console"/>
      <AppenderRef ref="debug_appender"/>
      <AppenderRef ref="info_appender"/>
      <AppenderRef ref="error_appender"/>
    </Root>

  </Loggers>
</Configuration>

AOP

添加依赖

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

例子

// 打印请求和响应信息
package com.imooc.mall.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


@Aspect
@Component
public class WebLogAspect {

    private final Logger log = LoggerFactory.getLogger(WebLogAspect.class);

    @Pointcut("execution(public * com.imooc.mall.controller.*.*(..)))")
    public void webLog() {

    }

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
        //收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        log.info("URL : " + request.getRequestURL().toString());
        log.info("HTTP_METHOD :" + request.getMethod());
        log.info("IP : " + request.getRemoteAddr());
        log.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "."
                + joinPoint.getSignature().getName());
        log.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
    }

    @AfterReturning(returning = "res", pointcut = "webLog()")
    public void doAfterReturning(Object res) throws JsonProcessingException {
        //处理完请求,返回内容
        log.info("RESPONSE : " + new ObjectMapper().writeValueAsString(res));
    }
}

Swagger

添加依赖

<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger2</artifactId>
  <version>2.9.2</version>
</dependency>
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger-ui</artifactId>
  <version>2.9.2</version>
</dependency>

使用

启动类添加 @EnableSwagger2 注解

添加 Swagger 配置文件

// SpringFoxConfig.java
package com.imooc.mall.config;

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.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@Configuration
public class SpringFoxConfig {

    //访问http://localhost:8083/swagger-ui.html可以看到API文档
    // .ignoredParameterTypes 用来排除不必要的参数
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build()
                .ignoredParameterTypes(HttpSession.class, HttpServletRequest.class, HttpServletResponse.class);
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("标题")
                .description("描述")
                .termsOfServiceUrl("")
                .version("v1.0.0")
                .contact(new Contact("Yang", "http://localhost:8083", "87******70@qq.com"))
                .build();
    }
}

添加地址映射文件

// ImoocMallWebMvcConfig.java
package com.imooc.mall.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 描述:配置地址映射
 */
@Configuration
public class ImoocMallWebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html").addResourceLocations(
                "classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations(
                "classpath:/META-INF/resources/webjars/");
    }
}

在接口上添加 @ApiOperation(标题) 注解,修改显示标题名

pagehelper

添加依赖

<dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper-spring-boot-starter</artifactId>
  <version>1.2.13</version>
</dependency>

使用

@Override
public PageInfo listForAdmin(Integer pageNum, Integer pageSize) {
  PageHelper.startPage(pageNum, pageSize, "type,order_num");
  List<Category> categoryList = categoryMapper.selectList();
  PageInfo pageInfo = new PageInfo(categoryList);
  return pageInfo;
}

Redis 缓存

添加依赖

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

使用

项目结构

  • config:所有的配置
  • mapper(dao):持久层接口
  • controller:请求入口
  • service:逻辑层
  • domain(Po、entity、Pojo):表映射实体类,用于 Java 数据和数据库记录的映射,属性和表字段完全一致,用在 Service 层和 Mapper 层
  • dto:数据传输对象,属性一般和表一致,但会根据不同的业务场景适当增加减少属性,用在 Service 层和 Controller 层

注解

常用注解

注解说明
@springBootApplicationSpring Boot 启动注解
@ComponentScan("com")Spring Boot 扫描,默认只会扫描当前类所在包的子包
@MapperScan("com.xxx.demo.mapper")MyBatis 扫描
@Controller用于声明返回界面
@ReuqestMapping
@GetMapping
@PostMapping
@Resource
@Autowried
@Repository
@ResponseBody
@RestController用于声明返回文本数据,一般返回 JSON,相当于 @Controller@ResponseBody 的结合
@Value("${变量名:默认值}")读取 application.properties 配置项
@RequestParam
@PathVariable
@Mapper
@select

参数校验

注解说明
@Valid需要验证
@NotNull非空
@Max(value)最大值
@Size(max,min)字符串长度范围限制

配置

默认配置项

  • resources 目录和 resources/config 目录下同时存在 application.properties 配置文件,则有限使用 resources/config 中的配置项
配置说明
server.port端口号

自定义配置

properties 方式

# application.properties
name=Yang
age=28
gender=

# 可以使用 x.x 的方式,获取时为 ${x.x}
package com.imooc.springbootlearn;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PersonController {
    @Value("${name}")
    private String name;
    @Value("${age}")
    private Integer age;
    @Value("${gender}")
    private String gender;

    @GetMapping("person")
    public String printInfo() {
        return "姓名:" + name + " 年龄:" + age + " 性别:" + gender;
    }
}

Java 代码方式

# application.properties
person.name=Yang
person.age=28
person.gender=nan
package com.imooc.springbootlearn;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "person")
public class PersonConfig {
    String name;
    Integer age;
    String gender;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
}
package com.imooc.springbootlearn;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PersonController {
    @Autowired
    PersonConfig personConfig;

    @GetMapping("person")
    public String printInfo() {
        return "姓名:" + personConfig.name + " 年龄:" + personConfig.age + " 性别:" + personConfig.gender;
    }
}
<!-- 如果遇到 IDEA 提示警告,可添加以下依赖 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>

请求参数

package com.jiawa.wiki.controller;

import org.springframework.web.bind.annotation.*;

@RestController
// 加入公共前缀
@RequestMapping("/api")
public class RequestTestController {

    // 初始请求
    @GetMapping("/test")
    public String test() {
        return "test";
    }

    // 多个 URI 指向同一处理程序
    @GetMapping({"/multitest1", "/multitest2"})
    public String multitest() {
        return "multitest";
    }

    // 若请求中无此参数,不会报错,得到的数据为 null
    @GetMapping("/test1")
    public String test1(Integer num) {
        return "num:" + num;
    }

    // @RequestParam 若请求中无 num 参数,会报 400 请求错误
    @GetMapping("/test2")
    public String test2(@RequestParam Integer num) {
        return "num:" + num;
    }

    // 请求参数设置默认值
    @GetMapping("/test3")
    public String test3(@RequestParam(defaultValue = "4") Integer num) {
        return "num:" + num;
    }

    // 请求参数设置别名
    @GetMapping("/test4")
    public String test4(@RequestParam(value = "num") Integer number) {
        return "num:" + number;
    }

    // @PathVariable 若请求路径参数中无 num 参数,会报 400 请求错误
    @GetMapping("/test5/{num}")
    public String test5(@PathVariable Integer num) {
        return "num:" + num;
    }
}

UUID

通用唯一识别码

  • 作用:防止重名、防止爬图
  • 生成规则:日期和时间、MAC 地址、HashCode、随机数

小技巧

修改启动字符

resources 文件夹中新建 banner.txt 文件

重启服务之后便会输出 banner.txt 中的字符

集成热部署

步骤一:pom.xml 添加依赖

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

步骤二:设置自动构建

  • 设置 - 构建、执行、部署 - 编译器 - 自动构建项目(打勾)

步骤三:设置 IDEA 注册表

  • 双击 Shift 键调出搜索框,搜索 Register(若编辑器已汉化则搜索 注册表
  • 进入后在 compiler.automake.allow.when.app.running 项打勾

待解决

  • LoggerFactory
  • logback 日志级别都有哪些?
  • slf4j, logback, log4j 是什么关系?
上次编辑于:
贡献者: sunzhenyang