1、创建后端项目
pom文件所需要的依赖
<dependencies>
<!-- SpringBoot-Web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MySQL依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- MybatisPlus和SpringBoot整合-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!-- 适用版本:mybatis-plus-generator代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
<!-- Freemarker模板引擎依赖-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
<!-- 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>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 加入log4j2的日志框架 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- 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-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、上传项目到码云
项目地址:https://gitee.com/yangcunle/YangCunle-Blog
3、整合MyBatisPlus
3.1配置乐观锁和分页插件
@Configuration
public class MyBatisPlusConfig {
/**
* 注册乐观锁插件和分页插件
* 不同版本的配置插件不一样(本次是用的是最新的版本3.5.1)
* 详情见MyBatisPlus官方文档:https://baomidou.com
* @return
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//添加乐观锁
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
//添加分页
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
}
}
3.2插入修改的填充策略
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入时的填充策略
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
//setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
/**
* 修改时的填充策略
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
3.3MyBatisPlus代码生成器
public class MyBatisPlusGenerator {
public static void main(String[] args) {
//数据库相关配置
String url = "jdbc:mysql://119.23.106.219:3306/ycl_blog?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC";
String username = "root";
String password = "ycl1207";
String projectPath = System.getProperty("user.dir");
//表名集合
List<String> tables = new ArrayList<>();
tables.add("t_user");
FastAutoGenerator.create(url, username, password)
//全局配置
.globalConfig(builder -> {
builder.author("YangCunle") // 设置作者
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.dateType(DateType.ONLY_DATE)
.outputDir(projectPath + "/src/main/java"); // 指定输出目录
})
//包配置
.packageConfig(builder -> {
builder.parent("com.yangcunle.blog") // 设置父包名
//设置包的命名
.entity("entity")
.service("service")
.serviceImpl("service.impl")
.controller("controller")
.mapper("mapper")
.xml("mapper")
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, projectPath + "/src/main/resources/mapper/")); // 设置mapperXml生成路径
})
//策略配置
.strategyConfig(builder -> {
builder.addInclude(tables) // 设置需要生成的表名
.addTablePrefix("t_")// 设置过滤表前缀
// 控制器配置:controllerBuilder
.controllerBuilder()
.enableHyphenStyle()//开启驼峰命名转字符
.enableRestStyle()//设置@RestController注解
// 逻辑层配置:serviceBuilder
.serviceBuilder()
.formatServiceFileName("%sService")//格式化 service 接口文件名称
.formatServiceImplFileName("%sServiceImpl")//格式化 serviceImpl 接口文件名称
// 实体类配置:entityBuilder
.entityBuilder()
.enableLombok()//设置Lombok
.enableTableFieldAnnotation()//开启生成实体时生成字段注解
.idType(IdType.AUTO)//设置主键类型:自增
.versionColumnName("version")//乐观锁
.logicDeleteColumnName("deleted")//逻辑删除
.addTableFills(new Column("create_time", FieldFill.INSERT), new Column("update_time", FieldFill.INSERT_UPDATE))//添加、修改时间自动填充
// Mapper配置:mapperBuilder
.mapperBuilder()
.enableBaseResultMap()//mapper自动生成通用查询映射结果
.enableBaseColumnList();//mapper自动生成通用列
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}
3.4一键生成代码
4、统一异常处理
统一异常处理包括:全局异常处理、特殊异常处理、自定义异常处理
4.1全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
//获取日志记录器对象
private final Logger logger = Logger.getLogger(GlobalExceptionHandler.class);
/**
* 处理运行时异常
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(value = RuntimeException.class)
public CommonResult handler(RuntimeException e) {
logger.error("运行时异常:{}" + e.getMessage());
return CommonResult.failed("博客系统貌似出现了问题o(╥﹏╥)o,请联系管理员处理。微信:YCL357486967");
}
}
4.2特殊异常处理
我们知道的一些异常可以列举出来,进行捕获,这里以除数不能为0举例
如果不处理,就会报以下错误:
/**
* 特殊异常处理 :ArithmeticException
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(value = ArithmeticException.class)
public CommonResult handler(ArithmeticException e) {
logger.error("除数不能为0异常:{}" + e.getMessage());
return CommonResult.failed(e.getMessage());
}
成功捕获:
4.3自定义异常处理
自己创建一个自定义异常类:BlogException 继承运行时异常 RuntimeException
@Data
public class BlogException extends RuntimeException {
private Integer code;
private String message;
public BlogException(Integer code, String message) {
super(message);
this.code = code;
this.message = message;
}
public BlogException(ResultCode ResultCode) {
super(ResultCode.getMessage());
this.code = ResultCode.getCode();
this.message = ResultCode.getMessage();
}
}
在全局异常处理中加入捕获自定义异常
/**
* 自定义异常处理
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(value = BlogException.class)
public CommonResult handler(BlogException e) {
logger.error("自定义异常:{}" + e.getMessage());
return CommonResult.failed(e.getMessage());
}
5、封装统一返回结果工具类
public class ResultUtil<T> {
// 状态码
private Integer code;
// 消息
private String msg;
// 数据
private T data;
public ResultUtil(T data) {
this.data = data;
}
/**
* 成功(无返回数据)
* @return
*/
public static ResultUtil success() {
ResultUtil result = new ResultUtil<>();
result.setCode(ResponseCode.SUCCEED);
result.setMsg(ResponseMsg.SUCCEED);
return result;
}
/**
* 成功(有返回数据)
* @param data
* @param <T>
* @return
*/
public static <T> ResultUtil<T> success(T data) {
ResultUtil<T> result = new ResultUtil<>(data);
result.setCode(ResponseCode.SUCCEED);
result.setMsg(ResponseMsg.SUCCEED);
return result;
}
/**
* 错误
* @param code
* @param msg
* @return
*/
public static ResultUtil error(Integer code, String msg) {
ResultUtil result = new ResultUtil();
result.setCode(code);
result.setMsg(msg);
return result;
}
}
6、用户模块的接口开发
public class UserController {
//获取日志记录器对象
private final Logger logger = Logger.getLogger(UserController.class);
@Autowired
private UserService userService;
/**
* 分页查询用户列表
* @param username
* @param pageNum
* @param pageSize
* @return
*/
@GetMapping("/list")
public ResultUtil<Page<User>> list(String username,
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
@RequestParam(required = false, defaultValue = "10") Integer pageSize) {
logger.info("查询用户列表开始:入参{username}:" + username);
LambdaQueryWrapper<User> query = Wrappers.<User>lambdaQuery().orderByDesc(User::getId);
if (!StringUtils.isEmpty(username)) {
query.like(User::getUsername, username);
}
Page<User> userPage = userService.page(new Page<>(pageNum, pageSize), query);
return ResultUtil.success(userPage);
}
/**
* 保存用户
* @param user
* @return
*/
@PostMapping("/save")
public ResultUtil<Boolean> save(@RequestBody User user) {
logger.info("添加用户:入参{user}:" + user.toString());
boolean result = userService.save(user);
return ResultUtil.success(result);
}
/**
* 修改用户信息
* @param user
* @return
*/
@PostMapping("/update")
public ResultUtil<Boolean> update(@RequestBody User user) {
logger.info("修改用户:入参{user}:" + user.toString());
boolean result = userService.updateById(user);
return ResultUtil.success(result);
}
/**
* 查看用户信息
* @param id
* @return
*/
@GetMapping("/read")
public ResultUtil<User> read(Integer id) {
logger.info("查看用户信息:入参{id}:" + id);
User user = userService.getById(id);
return ResultUtil.success(user);
}
/**
* 删除用户
* @param id
* @return
*/
@GetMapping("/delete")
public ResultUtil<Boolean> delete(Integer id) {
logger.info("删除用户信息:入参{id}:" + id);
boolean result = userService.removeById(id);
return ResultUtil.success(result);
}
}
7、ApiPost测试接口
https://console-docs.apipost.cn/preview/e66f1e46125af959/222ee42959f879ef
文档支持在线查看
用户列表支持分页查询
http://localhost:8081/user/list
返回结果
{
"code": 0,
"msg": "成功",
"data": {
"records": [
{
"id": 3,
"username": "ycl",
"password": "123",
"role": 2,
"email": "123@qq.com",
"phone": "123",
"age": null,
"headImg": null,
"createTime": "2021-08-02T08:11:47.000+00:00",
"updateTime": "2021-08-02T08:11:47.000+00:00",
"deleted": 0
},
{
"id": 2,
"username": "乐多多",
"password": "123456",
"role": 2,
"email": "123456@qq.com",
"phone": "123456",
"age": null,
"headImg": null,
"createTime": "2021-08-02T08:06:14.000+00:00",
"updateTime": "2021-08-02T08:06:14.000+00:00",
"deleted": 0
},
{
"id": 1,
"username": "admin",
"password": "admin",
"role": 1,
"email": "357487967@qq.com",
"phone": "15971397103",
"age": 25,
"headImg": null,
"createTime": "2021-08-02T10:33:11.000+00:00",
"updateTime": "2021-08-02T10:33:15.000+00:00",
"deleted": 0
}
],
"total": 3,
"size": 10,
"current": 1,
"orders": [],
"optimizeCountSql": true,
"searchCount": true,
"countId": null,
"maxLimit": null,
"pages": 1
}
}