image.png

1、创建后端项目

pom文件所需要的依赖

  1. <dependencies>
  2. <!-- SpringBoot-Web依赖-->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-web</artifactId>
  6. </dependency>
  7. <!-- MySQL依赖-->
  8. <dependency>
  9. <groupId>mysql</groupId>
  10. <artifactId>mysql-connector-java</artifactId>
  11. <scope>runtime</scope>
  12. </dependency>
  13. <!-- MybatisPlusSpringBoot整合-->
  14. <dependency>
  15. <groupId>com.baomidou</groupId>
  16. <artifactId>mybatis-plus-boot-starter</artifactId>
  17. <version>3.5.1</version>
  18. </dependency>
  19. <!-- 适用版本:mybatis-plus-generator代码生成器-->
  20. <dependency>
  21. <groupId>com.baomidou</groupId>
  22. <artifactId>mybatis-plus-generator</artifactId>
  23. <version>3.5.1</version>
  24. </dependency>
  25. <!-- Freemarker模板引擎依赖-->
  26. <dependency>
  27. <groupId>org.freemarker</groupId>
  28. <artifactId>freemarker</artifactId>
  29. <version>2.3.31</version>
  30. </dependency>
  31. <!-- Swagger相关依赖-->
  32. <dependency>
  33. <groupId>io.springfox</groupId>
  34. <artifactId>springfox-swagger2</artifactId>
  35. <version>2.9.2</version>
  36. </dependency>
  37. <dependency>
  38. <groupId>io.springfox</groupId>
  39. <artifactId>springfox-swagger-ui</artifactId>
  40. <version>2.9.2</version>
  41. </dependency>
  42. <!-- Lombok -->
  43. <dependency>
  44. <groupId>org.projectlombok</groupId>
  45. <artifactId>lombok</artifactId>
  46. <optional>true</optional>
  47. </dependency>
  48. <!-- 加入log4j2的日志框架 -->
  49. <dependency>
  50. <groupId>log4j</groupId>
  51. <artifactId>log4j</artifactId>
  52. <version>1.2.17</version>
  53. </dependency>
  54. <!-- Redis依赖-->
  55. <dependency>
  56. <groupId>org.springframework.boot</groupId>
  57. <artifactId>spring-boot-starter-data-redis</artifactId>
  58. </dependency>
  59. <!-- 测试依赖-->
  60. <dependency>
  61. <groupId>org.springframework.boot</groupId>
  62. <artifactId>spring-boot-starter-test</artifactId>
  63. <scope>test</scope>
  64. </dependency>
  65. </dependencies>

2、上传项目到码云

image.png
项目地址:https://gitee.com/yangcunle/YangCunle-Blog

3、整合MyBatisPlus

3.1配置乐观锁和分页插件

  1. @Configuration
  2. public class MyBatisPlusConfig {
  3. /**
  4. * 注册乐观锁插件和分页插件
  5. * 不同版本的配置插件不一样(本次是用的是最新的版本3.5.1)
  6. * 详情见MyBatisPlus官方文档:https://baomidou.com
  7. * @return
  8. */
  9. @Bean
  10. public MybatisPlusInterceptor mybatisPlusInterceptor() {
  11. MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
  12. //添加乐观锁
  13. mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
  14. //添加分页
  15. mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
  16. return mybatisPlusInterceptor;
  17. }
  18. }

3.2插入修改的填充策略

  1. @Component
  2. public class MyMetaObjectHandler implements MetaObjectHandler {
  3. /**
  4. * 插入时的填充策略
  5. * @param metaObject
  6. */
  7. @Override
  8. public void insertFill(MetaObject metaObject) {
  9. //setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
  10. this.setFieldValByName("createTime", new Date(), metaObject);
  11. this.setFieldValByName("updateTime", new Date(), metaObject);
  12. }
  13. /**
  14. * 修改时的填充策略
  15. * @param metaObject
  16. */
  17. @Override
  18. public void updateFill(MetaObject metaObject) {
  19. this.setFieldValByName("updateTime", new Date(), metaObject);
  20. }
  21. }

3.3MyBatisPlus代码生成器

  1. public class MyBatisPlusGenerator {
  2. public static void main(String[] args) {
  3. //数据库相关配置
  4. String url = "jdbc:mysql://119.23.106.219:3306/ycl_blog?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC";
  5. String username = "root";
  6. String password = "ycl1207";
  7. String projectPath = System.getProperty("user.dir");
  8. //表名集合
  9. List<String> tables = new ArrayList<>();
  10. tables.add("t_user");
  11. FastAutoGenerator.create(url, username, password)
  12. //全局配置
  13. .globalConfig(builder -> {
  14. builder.author("YangCunle") // 设置作者
  15. .enableSwagger() // 开启 swagger 模式
  16. .fileOverride() // 覆盖已生成文件
  17. .dateType(DateType.ONLY_DATE)
  18. .outputDir(projectPath + "/src/main/java"); // 指定输出目录
  19. })
  20. //包配置
  21. .packageConfig(builder -> {
  22. builder.parent("com.yangcunle.blog") // 设置父包名
  23. //设置包的命名
  24. .entity("entity")
  25. .service("service")
  26. .serviceImpl("service.impl")
  27. .controller("controller")
  28. .mapper("mapper")
  29. .xml("mapper")
  30. .pathInfo(Collections.singletonMap(OutputFile.mapperXml, projectPath + "/src/main/resources/mapper/")); // 设置mapperXml生成路径
  31. })
  32. //策略配置
  33. .strategyConfig(builder -> {
  34. builder.addInclude(tables) // 设置需要生成的表名
  35. .addTablePrefix("t_")// 设置过滤表前缀
  36. // 控制器配置:controllerBuilder
  37. .controllerBuilder()
  38. .enableHyphenStyle()//开启驼峰命名转字符
  39. .enableRestStyle()//设置@RestController注解
  40. // 逻辑层配置:serviceBuilder
  41. .serviceBuilder()
  42. .formatServiceFileName("%sService")//格式化 service 接口文件名称
  43. .formatServiceImplFileName("%sServiceImpl")//格式化 serviceImpl 接口文件名称
  44. // 实体类配置:entityBuilder
  45. .entityBuilder()
  46. .enableLombok()//设置Lombok
  47. .enableTableFieldAnnotation()//开启生成实体时生成字段注解
  48. .idType(IdType.AUTO)//设置主键类型:自增
  49. .versionColumnName("version")//乐观锁
  50. .logicDeleteColumnName("deleted")//逻辑删除
  51. .addTableFills(new Column("create_time", FieldFill.INSERT), new Column("update_time", FieldFill.INSERT_UPDATE))//添加、修改时间自动填充
  52. // Mapper配置:mapperBuilder
  53. .mapperBuilder()
  54. .enableBaseResultMap()//mapper自动生成通用查询映射结果
  55. .enableBaseColumnList();//mapper自动生成通用列
  56. })
  57. .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
  58. .execute();
  59. }
  60. }

3.4一键生成代码

image.png

4、统一异常处理

统一异常处理包括:全局异常处理、特殊异常处理、自定义异常处理

4.1全局异常处理

  1. @RestControllerAdvice
  2. public class GlobalExceptionHandler {
  3. //获取日志记录器对象
  4. private final Logger logger = Logger.getLogger(GlobalExceptionHandler.class);
  5. /**
  6. * 处理运行时异常
  7. * @param e
  8. * @return
  9. */
  10. @ResponseBody
  11. @ExceptionHandler(value = RuntimeException.class)
  12. public CommonResult handler(RuntimeException e) {
  13. logger.error("运行时异常:{}" + e.getMessage());
  14. return CommonResult.failed("博客系统貌似出现了问题o(╥﹏╥)o,请联系管理员处理。微信:YCL357486967");
  15. }
  16. }

4.2特殊异常处理

我们知道的一些异常可以列举出来,进行捕获,这里以除数不能为0举例
image.png
如果不处理,就会报以下错误:
image.png

  1. /**
  2. * 特殊异常处理 :ArithmeticException
  3. * @param e
  4. * @return
  5. */
  6. @ResponseBody
  7. @ExceptionHandler(value = ArithmeticException.class)
  8. public CommonResult handler(ArithmeticException e) {
  9. logger.error("除数不能为0异常:{}" + e.getMessage());
  10. return CommonResult.failed(e.getMessage());
  11. }

成功捕获:
image.png

4.3自定义异常处理

自己创建一个自定义异常类:BlogException 继承运行时异常 RuntimeException

  1. @Data
  2. public class BlogException extends RuntimeException {
  3. private Integer code;
  4. private String message;
  5. public BlogException(Integer code, String message) {
  6. super(message);
  7. this.code = code;
  8. this.message = message;
  9. }
  10. public BlogException(ResultCode ResultCode) {
  11. super(ResultCode.getMessage());
  12. this.code = ResultCode.getCode();
  13. this.message = ResultCode.getMessage();
  14. }
  15. }

在全局异常处理中加入捕获自定义异常

  1. /**
  2. * 自定义异常处理
  3. * @param e
  4. * @return
  5. */
  6. @ResponseBody
  7. @ExceptionHandler(value = BlogException.class)
  8. public CommonResult handler(BlogException e) {
  9. logger.error("自定义异常:{}" + e.getMessage());
  10. return CommonResult.failed(e.getMessage());
  11. }

测试一波:
image.png
自定义异常捕获成功
image.png

5、封装统一返回结果工具类

  1. public class ResultUtil<T> {
  2. // 状态码
  3. private Integer code;
  4. // 消息
  5. private String msg;
  6. // 数据
  7. private T data;
  8. public ResultUtil(T data) {
  9. this.data = data;
  10. }
  11. /**
  12. * 成功(无返回数据)
  13. * @return
  14. */
  15. public static ResultUtil success() {
  16. ResultUtil result = new ResultUtil<>();
  17. result.setCode(ResponseCode.SUCCEED);
  18. result.setMsg(ResponseMsg.SUCCEED);
  19. return result;
  20. }
  21. /**
  22. * 成功(有返回数据)
  23. * @param data
  24. * @param <T>
  25. * @return
  26. */
  27. public static <T> ResultUtil<T> success(T data) {
  28. ResultUtil<T> result = new ResultUtil<>(data);
  29. result.setCode(ResponseCode.SUCCEED);
  30. result.setMsg(ResponseMsg.SUCCEED);
  31. return result;
  32. }
  33. /**
  34. * 错误
  35. * @param code
  36. * @param msg
  37. * @return
  38. */
  39. public static ResultUtil error(Integer code, String msg) {
  40. ResultUtil result = new ResultUtil();
  41. result.setCode(code);
  42. result.setMsg(msg);
  43. return result;
  44. }
  45. }

6、用户模块的接口开发

  1. public class UserController {
  2. //获取日志记录器对象
  3. private final Logger logger = Logger.getLogger(UserController.class);
  4. @Autowired
  5. private UserService userService;
  6. /**
  7. * 分页查询用户列表
  8. * @param username
  9. * @param pageNum
  10. * @param pageSize
  11. * @return
  12. */
  13. @GetMapping("/list")
  14. public ResultUtil<Page<User>> list(String username,
  15. @RequestParam(required = false, defaultValue = "1") Integer pageNum,
  16. @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
  17. logger.info("查询用户列表开始:入参{username}:" + username);
  18. LambdaQueryWrapper<User> query = Wrappers.<User>lambdaQuery().orderByDesc(User::getId);
  19. if (!StringUtils.isEmpty(username)) {
  20. query.like(User::getUsername, username);
  21. }
  22. Page<User> userPage = userService.page(new Page<>(pageNum, pageSize), query);
  23. return ResultUtil.success(userPage);
  24. }
  25. /**
  26. * 保存用户
  27. * @param user
  28. * @return
  29. */
  30. @PostMapping("/save")
  31. public ResultUtil<Boolean> save(@RequestBody User user) {
  32. logger.info("添加用户:入参{user}:" + user.toString());
  33. boolean result = userService.save(user);
  34. return ResultUtil.success(result);
  35. }
  36. /**
  37. * 修改用户信息
  38. * @param user
  39. * @return
  40. */
  41. @PostMapping("/update")
  42. public ResultUtil<Boolean> update(@RequestBody User user) {
  43. logger.info("修改用户:入参{user}:" + user.toString());
  44. boolean result = userService.updateById(user);
  45. return ResultUtil.success(result);
  46. }
  47. /**
  48. * 查看用户信息
  49. * @param id
  50. * @return
  51. */
  52. @GetMapping("/read")
  53. public ResultUtil<User> read(Integer id) {
  54. logger.info("查看用户信息:入参{id}:" + id);
  55. User user = userService.getById(id);
  56. return ResultUtil.success(user);
  57. }
  58. /**
  59. * 删除用户
  60. * @param id
  61. * @return
  62. */
  63. @GetMapping("/delete")
  64. public ResultUtil<Boolean> delete(Integer id) {
  65. logger.info("删除用户信息:入参{id}:" + id);
  66. boolean result = userService.removeById(id);
  67. return ResultUtil.success(result);
  68. }
  69. }

7、ApiPost测试接口

image.png

https://console-docs.apipost.cn/preview/e66f1e46125af959/222ee42959f879ef
文档支持在线查看
image.png
用户列表支持分页查询

  1. http://localhost:8081/user/list

返回结果

  1. {
  2. "code": 0,
  3. "msg": "成功",
  4. "data": {
  5. "records": [
  6. {
  7. "id": 3,
  8. "username": "ycl",
  9. "password": "123",
  10. "role": 2,
  11. "email": "123@qq.com",
  12. "phone": "123",
  13. "age": null,
  14. "headImg": null,
  15. "createTime": "2021-08-02T08:11:47.000+00:00",
  16. "updateTime": "2021-08-02T08:11:47.000+00:00",
  17. "deleted": 0
  18. },
  19. {
  20. "id": 2,
  21. "username": "乐多多",
  22. "password": "123456",
  23. "role": 2,
  24. "email": "123456@qq.com",
  25. "phone": "123456",
  26. "age": null,
  27. "headImg": null,
  28. "createTime": "2021-08-02T08:06:14.000+00:00",
  29. "updateTime": "2021-08-02T08:06:14.000+00:00",
  30. "deleted": 0
  31. },
  32. {
  33. "id": 1,
  34. "username": "admin",
  35. "password": "admin",
  36. "role": 1,
  37. "email": "357487967@qq.com",
  38. "phone": "15971397103",
  39. "age": 25,
  40. "headImg": null,
  41. "createTime": "2021-08-02T10:33:11.000+00:00",
  42. "updateTime": "2021-08-02T10:33:15.000+00:00",
  43. "deleted": 0
  44. }
  45. ],
  46. "total": 3,
  47. "size": 10,
  48. "current": 1,
  49. "orders": [],
  50. "optimizeCountSql": true,
  51. "searchCount": true,
  52. "countId": null,
  53. "maxLimit": null,
  54. "pages": 1
  55. }
  56. }