前言
- 这里jdk版本是1.8(版本必须是java8或java11或java17)
- mysql版本是8.0以上的版本
目录
一、创建项目
由于java8比较稳定,所需这里项目创建时选择的java8版本,如果没有java8这个选项的话,可以将Server URL
改为https://start.aliyun.com/
spring boot版本是2.7.6,同时引入一些常用依赖:
项目创建成功后,先运行看能够运行成功,结果发现错误:Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
报错原因:由于我们在项目创建之初引入了Mysql Driver驱动依赖
,所以在项目启动的时候就会自动连接mysql,但是我们没有进行数据库的配置,所以我们需要编写一个配置文件进行数据库配置(application.yml
)。
- 数据库基础配置
yaml
server:
port: 8126
servlet:
context-path: /api
spring:
application:
name: cloud-picture-backend
# 数据库配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306
username: root
password: 111111
现在就可以正常运行了。
二、整合依赖
Mybatis Plus依赖
可以参考官方文档:https://baomidou.com/getting-started/#spring-boot2
- 在Maven的
pom.xml
中添加依赖,注意:添加mybatis plus依赖后,需要一处mybatis相关的依赖
,即引入Mybatis-Plus
之后不能再次引入Mybatis
和mybatis-spring-boot-starter
,否则会导致版本冲突问题:
xml
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.9</version>
</dependency>
- 首先项目中新建mapper目录,然后复制mapper的路径,在项目启动类中添加扫描Mapper的
@MapperScan
注解:
java
@SpringBootApplication
@MapperScan("com.yf.cloudpicturebackend.mapper")
public class CloudPictureBackendApplication {
public static void main(String[] args) {
SpringApplication.run(CloudPictureBackendApplication.class, args);
}
}
- 在application.yml中添加相应的配置(可以参照上面的mybatis plus官方文档):
yaml
mybatis-plus:
configuration:
# MyBatis 配置
map-underscore-to-camel-case: false
# 仅在开发环境打印日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
logic-delete-field: isDelete
logic-delete-value: 1
logic-not-delete-value: 0
Hutool工具库
可以参考官方文档:https://doc.hutool.cn/pages/index/#🍊maven
xml
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>
Knife4j
Knife4j是一个基于Swagger的接口文档工具(可以理解为Swagger的升级版),可以让我们快速了解项目中的接口,方便后续进行接口调试。简单说Knife4j的作用:我们写完代码后,Knife4j会自动生成接口文档
。
可以参考官方文档:https://doc.xiaominfo.com/docs/quick-start#spring-boot-2
新建controller包(用于存放API接口)
xml
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
进行Knife4j的相关yml配置:
yaml
# 接口文档配置
knife4j:
enable: true
openapi:
title: Knife4j官方文档
version: 1.0
group:
default:
group-name: 默认分组
api-rule: package
api-rule-resources:
- com.yf.cloudpicturebackend.controller
然后我们再次运行项目后会发现多了一个路径:
AOP切面编程
依赖引入:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
然后给启动类添加注解:
java
@EnableAspectJAutoProxy(exposeProxy = true)
exposeProxy = true
的作用:用于启动aspectj
自动代理功能。在Spring AOP中,通过该注解可以将代理对象暴露出来,方便在AOP切面中获取代理对象并进行操作。exposeProxy = true
就表示暴露代理对象。
三、通用代码基础
自定义异常
通过自定义异常对错误码进行收敛,便于前端统一进行处理。注意:
自定义错误码时最好跟主流的HTTP错误码含义(回忆一下常用的HTTP响应码:
400表示bad request
、401表示没权限
、403表示被禁止
、404表示没资源
)保持一致:
- 在
exception包
下创建错误码枚举类(ErrorCode.java)
java
@Getter
public enum ErrorCode {
SUCCESS(0, "ok"),
PARAMS_ERROR(40000, "请求参数错误"),
NOT_LOGIN_ERROR(40100, "未登录"),
NO_AUTH_ERROR(40101, "无权限"),
NOT_FOUND_ERROR(40400, "请求数据不存在"),
FORBIDDEN_ERROR(40300, "禁止访问"),
SYSTEM_ERROR(50000, "系统内部异常"),
OPERATION_ERROR(50001, "操作失败");
/**
* 状态码
*/
private final int code;
/**
* 信息
*/
private final String message;
ErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
}
java
/**
* 自定义业务异常
*/
@Getter
public class BusinessException extends RuntimeException {
/**
* 错误码
*/
private final int code;
public BusinessException(int code, String message) {
super(message);
this.code = code;
}
public BusinessException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.code = errorCode.getCode();
}
public BusinessException(ErrorCode errorCode, String message) {
super(message);
this.code = errorCode.getCode();
}
}
- 自定义业务异常:与内置异常类进行区分,便于定制化输出错误信息。
java
/**
* 自定义业务异常
*/
@Getter
public class BusinessException extends RuntimeException {
/**
* 错误码
*/
private final int code;
public BusinessException(int code, String message) {
super(message);
this.code = code;
}
public BusinessException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.code = errorCode.getCode();
}
public BusinessException(ErrorCode errorCode, String message) {
super(message);
this.code = errorCode.getCode();
}
}
- 封装一个
ThrowUtils类
(类似于断言类的方法),简化抛异常的代码:
全局响应类封装
我们知道,每个后端接口都要返回调用吗、数据、调用信息;而前端则可以根据这些信息进行相应的处理。所以我们可以进行一个全局响应结果类
的封装、这样便于前端同意获取这些信息。
通用响应类如下:
java
@Data
public class BaseResponse<T> implements Serializable {
private int code;
private T data;
private String message;
public BaseResponse(int code, T data, String message) {
this.code = code;
this.data = data;
this.message = message;
}
public BaseResponse(int code, T data) {
this(code, data, "");
}
public BaseResponse(ErrorCode errorCode) {
this(errorCode.getCode(), null, errorCode.getMessage());
}
}
全局异常处理器
在exception包下创建GlobalExceptionHandler
:
java
/**
* 全局异常处理器
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public BaseResponse<?> businessExceptionHandler(BusinessException e) {
log.error("BusinessException", e);
return ResultUtils.error(e.getCode(), e.getMessage());
}
@ExceptionHandler(RuntimeException.class)
public BaseResponse<?> runtimeExceptionHandler(RuntimeException e) {
log.error("RuntimeException", e);
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");
}
}
请求包装类
我们对于分页
、删除某条数据
这类通用的请求,可以封装统一的请求包装类,用于接受前端传来的参数。
- 在
commen包下
创建PageRequest.java类
(分页请求包装类如下):
java
/**
* 通用的分页请求类
*/
@Data
public class PageRequest {
/**
* 当前页号
*/
private int current = 1;
/**
* 页面大小
*/
private int pageSize = 10;
/**
* 排序字段
*/
private String sortField;
/**
* 排序顺序(默认降序)
*/
private String sortOrder = "descend";
}
- 在
commen包下
创建DeleteRequest.java类
(删除请求包装类如下):
java
/**
* 通用的删除请求类
*/
@Data
public class DeleteRequest implements Serializable {
/**
* id
*/
private Long id;
private static final long serialVersionUID = 1L;
}
四、跨域问题
对于本地开发,前端启动一个项目会占用一个端口,后端启用一个项目又会占用另外一个端口,两个端口号是不一致的。比如使用前端localhost:5182页面
去请求后端localhost:8135接口
,这个时候就会出现跨域问题(跨域问题只在浏览器中出现)。解决该问题有如下两个解决方案
- 后端支持跨域
- 代理:比如
前端localhost:5182
网站可以通过一些工具访问前端localhost:5182/user
。换句话说只要localhost:5182访问localhost:5182/user这个地址
,这个时候代理就会自动把请求转发到localhost:8175后端
;对于前端来说访问的依然是localhost:5182,但实际上已经把请求转发给localhost:8175了。
现在我们通过第一种,即后端的方式来解决跨域问题:
- 新建config包,用于存放所有的配置相关代码。全局跨域配置代码如下:
java
/**
* 全局跨域配置
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 覆盖所有请求
registry.addMapping("/**")
// 允许发送 Cookie
.allowCredentials(true)
// 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突)
.allowedOriginPatterns("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.exposedHeaders("*");
}
}
五、运行项目
现在来到最后一步,运行项目看是否能够运行成功,移除controller包下的其它代码,然后新建一个/health接口
用于健康检查:
java
@RestController
@RequestMapping("/")
public class MainController {
/**
* 健康检查
*/
@GetMapping("/health")
public BaseResponse<String> health() {
return ResultUtils.success("ok");
}
}
好了,到这里初始化就成功了。