项目总览
大约 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&characterEncoding=UTF-8&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 层
注解
常用注解
注解 | 说明 |
---|---|
@springBootApplication | Spring 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
中的字符
字符生成器(图片转):https://www.degraeve.com/img2txt.php
如果不成功可以尝试在
application.properties
文件中添加以下内容spring.banner.location=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
项打勾
![](https://cdn.jsdelivr.net/gh/sunzhenyang/blog-img/img/20210822225250.png)
待解决
LoggerFactory
- logback 日志级别都有哪些?
- slf4j, logback, log4j 是什么关系?