springboot2021-07-12

欧阳德运
2023-12-01

Day01

1.项目介绍

1.1.背景及概述

1.1.1.背景

随着智能手机的普及,人们更加习惯于通过手机来看新闻。由于生活节奏的加快,很多人只能利用碎片时间来获取信息,因此,对于移动资讯客户端的需求也越来越高。黑马头条项目正是在这样背景下开发出来。黑马头条项目采用当下火热的微服务+大数据技术架构实现。本项目主要着手于获取最新最热新闻资讯,通过大数据分析用户喜好精确推送咨询新闻。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aiHEyLxR-1626092860432)(assets/1603238772138.png)]

1.1.2.概述

黑马头条项目是一个新闻客户端项目。碎片化、切换频繁、社交化和个性化现如今成为人们阅读行为的标签。黑马头条对海量信息进行搜集,通过系统计算分类,分析用户的兴趣进行推送从而满足用户的需求。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9iARdnSl-1626092860435)(assets/1603238800443.png)]

(面试题:请简单介绍你的项目

1.介绍这个项目是什么项目,为什么要做这个项目 (项目介绍入口)

2.介绍这个项目的平台,及功能(项目的功能介绍)

3.项目的技术架构(哪些平台,用了什么技术)

4.哪些功能是你做的(项目功能介绍)

5.用什么技术做的(项目功能介绍)

6.做的时候有什么问题(项目功能介绍)

7.如何解决的(项目功能介绍)

1.1.3.项目术语定义

  • 项目:泛指黑马头条整个项目或某一项目模块

  • 工程:泛指黑马头条某一项目的源码工程

    用户角色划分

  • 用户:泛指黑马头条APP用户端用户

  • 自媒体人:泛指通过黑马自媒体系统发送文章的用户

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-anJ4eEDO-1626092860437)(assets/1604539437268.png)]

  • 管理员:泛指黑马头条管理系统的使用用户(公司内部的工作人员)

    平台划分

  • App:泛指黑马头条APP

  • WeMedia:泛指黑马头条自媒体系统

  • Admin:泛指黑马头条管理系统(内部工作人员使用的系统)

1.2.功能需求说明

1.2.1.功能架构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3FSgR8eN-1626092860440)(assets/1603238863382.png)]

1.2.2.App主要功能大纲

  • 频道栏:用户可以通过此功能添加自己感兴趣的频道,在添加标签时,系统可依据用户喜好进行推荐
  • 文章列表:需要显示文章标题、文章图片、评论数等信息,且需要监控文章是否在APP端展现的行为
  • 搜索文章:联想用户想搜索的内容,并记录用户的历史搜索信息
  • 个人中心:用户可以在其个人中心查看收藏、关注的人、以及系统设置等功能
  • 查看文章:用户点击文章进入查看文章页面,在此页面上可进行点赞、评论、不喜欢、分享等操作;除此之外还需要收集用户查看文章的时间,是否看我等行为信息
  • 实名认证:用户可以进行身份证认证和实名认证,实名认证之后即可成为自媒体人,在平台上发布文章
  • 注册登录:登录时,验证内容为手机号登录/注册,通过手机号验证码进行登录/注册,首次登录用户自动注册账号。

1.2.3.自媒体端功能大纲

  • 内容管理:自媒体用户管理文章页面,可以根据条件进行筛选,文章包含草稿、已发布、未通过、已撤回状态。用户可以对文章进行修改,上/下架操作、查看文章状态等操作
  • 评论管理:管理文章评论页面,显示用户已发布的全部文章,可以查看文章总评论数和粉丝评论数,可以对文章进行关闭评论等操作
  • 素材管理:管理自媒体文章发布的图片,便于用户发布带有多张图片的文章
  • 图文数据:自媒体人发布文章的数据:阅读数、评论数、收藏了、转发量,用户可以查看对应文章的阅读数据
  • 粉丝画像:内容包括:粉丝性别分布、粉丝年龄分布、粉丝终端分布、粉丝喜欢分类分布

1.2.4.平台管理端功能大纲

  • 用户管理:系统后台用来维护用户信息,可以对用户进行增删改查操作,对于违规用户可以进行冻结操
  • 用户审核:管理员审核用户信息页面,用户审核分为身份审核和实名审核,身份审核是对用户的身份信息进行审核,包括但不限于工作信息、资质信息、经历信息等;实名认证是对用户实名身份进行认证
  • 内容管理:管理员查询现有文章,并对文章进行新增、删除、修改、置顶等操作
  • 内容审核:管理员审核自媒体人发布的内容,包括但不限于文章文字、图片、敏感信息等
  • 频道管理:管理频道分类界面,可以新增频道,查看频道,新增或修改频道关联的标签
  • 网站统计:统计内容包括:日活用户、访问量、新增用户、访问量趋势、热门搜索、用户地区分布等数据
  • 内容统计:统计内容包括:文章采集量、发布量、阅读量、阅读时间、评论量、转发量、图片量等数据
  • 权限管理:超级管理员对后台管理员账号进行新增或删除角色操作

1.2.5.其他需求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8KEc1El0-1626092860442)(assets/1603239068068.png)]

1.2.6.交互需求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g5aakUH3-1626092860443)(assets/1603239090975.png)]

1.3.技术架构说明

包括前端(Weex、Vue、Echarts、WS)、网关(GateWay)、DevOps(单元测试、代码规范)

服务层中包括中间件(Kafka)、索引、微服务、大数据存储等重难点技术

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WObVQoyr-1626092860444)(assets/1603335976271.png)]

  • Weex+Vue+WebSocket :使用Weex跨平台开发工具,整合集成VUE框架,完成黑马头条移动端功能开发,并集成WebSocket实现即时消息(文章推荐、私信)的推送

  • Vue+Echarts : 自媒体系统使用Vue开发关键,集成Echarts图表框架,完成相关粉丝画像、数据分析等功能

  • Vue+Echarts+WebSocket : 管理系统也是使用Vue开发,集成Echarts,完成网站统计、内容统计等功能,集成WebSocket,实现系统看板实时数据自动化更新

  • Spring-Cloud-Gateway : 微服务之前架设的网关服务,实现服务注册中的API请求路由,以及控制流速控制和熔断处理都是常用的架构手段,而这些功能Gateway天然支持

  • PMD&P3C : 静态代码扫描工具,在项目中扫描项目代码,检查异常点、优化点、代码规范等,为开发团队提供规范统一,提升项目代码质量

  • Junit : 在持续集成思想中,单元测试偏向自动化过程,项目通过Junit+Maven的集成实现这种过程

  • 运用Spring Boot快速开发框架,构建项目工程;并结合Spring Cloud全家桶技术,实现后端个人中心、自媒体、管理中心等微服务。

  • 运用WebMagic爬虫技术,完善系统内容自动化采集

  • 运用Kafka完成内部系统消息通知;与客户端系统消息通知;以及实时数据计算

  • 运用MyCat数据库中间件计算,对系统数据进行分开分表,提升系统数据层性能

  • 运用Redis缓存技术,实现热数据的计算,NoSession等功能,提升系统性能指标

  • 运用Zoookeeper技术,完成大数据节点之后的协调与管理,提升系统存储层高可用

  • 使用Mysql存储用户数据,以保证上层数据查询的高性能

  • 使用Mongo存储用户热数据,以保证用户热数据高扩展和高性能指标

  • 使用FastDFS作为静态资源存储器,在其上实现热静态资源缓存、淘汰等功能

  • 运用Habse技术,存储系统中的冷数据,保证系统数据的可靠性

  • 运用ES搜索技术,对冷数据、文章数据建立索引,以保证冷数据、文章查询性能

  • 运用Sqoop、Kettle等工具,实现大数据的离线入仓;或者数据备份到Hadoop

  • 运用Spark+Hive进行离线数据分析,实现系统中各类统计报表

  • 运用Spark Streaming + Hive+Kafka实现实时数据分析与应用;比如文章推荐

  • 运用Neo4j知识图谱技术,分析数据关系,产出知识结果,并应用到上层业务中,以帮助用户、自媒体、运营效果/能力提升。比如粉丝等级计算

  • 运用AI技术,来完成系统自动化功能,以提升效率及节省成本。比如实名认证自动化

2.环境搭建

2.1.数据库设计规范及导入数据库

2.1.1.数据库设计

2.1.1.1.ER图设计

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6TXM1JUW-1626092860445)(assets/1603336699020.png)]

er图设计划分出了9个库,各个库主要解决的是某一个特定的业务。

数据库设计规范,详见资料文件夹下《黑马头条-数据库规范设计说明书.md》文件。

PowerDesinger工具使用,详见资料文件夹下’powerdesinger的基本使用’文件夹里的《powerdesinger的基本使用》文件。

2.1.1.2.分库设计

黑马头条项目采用的分库分表设计,因为业务比较复杂,后期的访问量巨大,为了分摊数据库的压力,整个项目用的不只是一个数据库。其中核心库有7个,每一个数据库解决的是一个业务点,非常接近与实际项目设计。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5UIAoYRX-1626092860446)(assets/1603337058718.png)]

创建数据库及表,可以参考资料中的sql脚本。

2.1.1.3.核心数据流转图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hR007BDq-1626092860447)(assets/1603337482300.png)]

说明:整个项目其核心数据为文章信息,上图主要说明文章的数据流转

1 爬虫系统从外网采集数据后入爬虫库,即爬虫库中保存了一份采集的文章信息。

2 自媒体人可以通过发布文章后首先进入自媒体库

3 爬虫文章和自媒体文章最后都要经过审核成功后入appinfo库,这里面的文章信息,最终是要给app端用户所查看。

4 在app端用户查看的时候,需要记录用户的一些行为,如转发、评论、点赞等需要入用户行为库

2.1.1.4.冗余设计

黑马头条项目全部采用逻辑关联,没有采用主外键约束(没有强关联,都是伪关联)。也是方便数据源冗余,尽可能少的使用多表关联查询。冗余是为了效率,减少join。单表查询比关联查询速度要快。某个访问频繁的字段可以冗余存放在两张表里,不用关联了。

如查询一个订单表需要查询该条订单的用户名称,就必须join另外用户表,如果业务表很大,那么就会查询的很慢,这个时候我们就可以使用冗余来解决这个问题,在新建订单的同时不仅仅需要把用户ID存储,同时也需要存储用户的名称,这样我们在查询订单表的时候就不需要去join另外用户表,也能查询出该条订单的用户名称。这样的冗余可以直接的提高查询效率,单表更快。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EVXMsq9j-1626092860448)(assets/1603337701393.png)]

2.2.初始化工程导入及环境说明

2.2.1.主体结构说明

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wF7S3xty-1626092860449)(assets/1603338099263.png)]

后端工程基于Spring-boot 2.1.5.RELEASE 版本构建,工程父项目为heima-leadnews,并通过继承方式集成Spring-boot

【父项目下分4个公共子项目】:

  • heima-leadnews-common : 是整个工程的配置核心,包括所有集成三方框架的配置定义,比如redis、kafka等。除此之外还包括项目每个模块及整个项目的常量定义;

  • **heima-leadnews-model :**项目中用到的Dto、Pojo、Mapper、Enums定义工程;

  • heima-leadnews-utils : 工程公用工具类项目,包含加密/解密、Date、JSON等工具类;

  • heima-leadnew-apis : 整个项目微服务暴露的接口的定义项目,按每个模块进行子包拆分(本质上就是对controller的方法(接口)进行interface声明);

  • 关系说明

    • apis项目引入common和model项目,common和model项目会引入所需的依赖包以及公共配置和pojo
    • uitls项目引入model项目,并引入了自己所需的依赖包

【多个微服务】:

  • **heima-leadnews-login:**用于实现APP+自媒体端用户的登录与注册功能;
  • **heima-leadnews-user:**用于实现APP端用户中心的功能,比如我的收藏、我的粉丝等功能;
  • **heima-leadnews-article:**用于实现APP端文章的获取与搜索等功能;还包括频道、标签等功能;
  • **heima-leadnews-behavior:**用于实现APP端各类行为数据的上传服务;
  • **heima-leadnews-quartz:**用于封装项目中所有的调度计算任务;
  • **heima-leadnews-wemedia:**用于实现自媒体管理端的功能;
  • **heima-leadnews-admin:**用于实现后台管理系统的功能;
  • **heima-leadnews-gateway:**网关

2.2.2.后端通用工程搭建

2.2.2.1.开发环境说明

项目依赖环境(需提前安装好):

  • JDK1.8
  • Intellij Idea
  • Tomcat 8.5
  • Git
2.2.2.2.IDEA开发工具配置

1.设置本地仓库,建议使用资料中提供好的仓库

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4PMgYSFX-1626092860450)(assets/1603338800024.png)]

2.设置项目编码格式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ISwHWOj2-1626092860450)(assets/1603338842601.png)]

3.后端初始项目导入

在今天资料目录的初始工程目录找到heima-leadnews.zip文件,拷贝到一个没有中文和空格的目录,解压缩,使用idea打开即可。

注意

资料中提供的初始项目,有可能问题,在父工程的pom.xml文件中的dependencyManagement标签中会报错。

解决方式:将报错的依赖配置,剪切到dependencies就会自动下载,下载好之后在剪切回dependencyManagement中。

扩展

没有使用课程资料中的仓库,导入项目之后,在父工程的pom.xml文件中会有一些依赖报红(依赖没有下载引起的),这个时候可以将报红的依赖导入的中,进行下载,但是xxl-job-core依赖会下载可能会下载失败(这是因为aliyun仓库可能没有这个依赖),这时可以讲随堂笔记中的依赖,拷贝到本地仓库的com目录下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CdbdM7JJ-1626092860451)(assets/1603346912421.png)]

此外还有可能maven-resources-plugin也可能会报红,可以改为以下的配置

<plugin>
   <artifactId>maven-resources-plugin</artifactId>
   <groupId>org.apache.maven.plugins</groupId>
   <version>3.1.0</version>
   <configuration>
       <useDefaultDelimiters>true</useDefaultDelimiters>
   </configuration>
</plugin>
2.2.2.3.SpringBoot工程构建使用

1.创建Springboot项目,必须联网

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EB2lyukG-1626092860452)(assets/image-20210611200753091.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JPbjCcXM-1626092860453)(assets/image-20210611200850164.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2xK8n9jP-1626092860454)(assets/image-20210611200922220.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-28VckQwk-1626092860456)(assets/image-20210611201004217.png)]

2.修改项目的pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>
    <groupId>com.itheima</groupId>
    <artifactId>springboot_quickstart</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot_quickstart</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

注意:删除单元测试类,否则报错。

3.在引导类所在目录创建controller目录,然后再其中创建Controller。

@RestController
@RequestMapping("/quickstart")
public class QuickStartController {

    @RequestMapping("/show")
    public String show(){

        return "Hello Springboot";
    }

}

4.在application.properties文件中配置tomcat访问端口。

server.port=9001

application.properties可以用application.yml替换

server:
  port: 9001

5.通过启动引导类来启动项目,浏览器输入地址:http://localhost:9001/quickstart/show进行访问

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AQgEoFSC-1626092860456)(assets/image-20210611201915587.png)]

6.整合lombok插件,操作实体类

lombok可以自动的生成实体类属性的set/get方法,能提升我们编写代码的效率。

6.1.IDEA下载lombok插件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r57ZXWOW-1626092860458)(assets/image-20210611202223823.png)]

6.2.在项目的pom.xml文件中引入lombok依赖

 <!-- lombok -->
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <version>1.18.8</version>
</dependency>

6.3.创建实体类,使用lombok进行标识

@Data  //lombok注解,通过lombok构建属性的set/get方法
public class AdChannel{

    private Integer id;

    private String name;

    private String description;

    private Boolean isDefault;

    private Boolean status;

    private Integer ord;

    private Date createdTime;

}

6.4.修改Controller中的代码

@RestController
@RequestMapping("/quickstart")
public class QuickStartController {

    @RequestMapping("/show")
    public AdChannel show(){


        AdChannel adChannel = new AdChannel();
        adChannel.setId(1);
        adChannel.setName("张三");


        return adChannel;
    }

}

6.5.重新启动项目,重新进行访问

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nOxjfsUu-1626092860459)(assets/image-20210611203049316.png)]

7.整合mybatis-plus,操作数据库。

7.1.在项目的pom.xml文件中引入相关依赖

<!-- mybatis相关 -->
        <!-- mysql驱动依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
        <!-- mybatis依赖 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.1</version>
        </dependency>
        <!-- mybatis-plus依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.1</version>
        </dependency>

7.2.项目的application.yml文件中配置数据库连接

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/leadnews_admin1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: root
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
  # 设置映射文件扫描
  mapper-locations: classpath*:mybatis/*.xml
  # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  type-aliases-package: com.ithiema.springboot_quickstart.pojos

7.3.修改AdChannel代码

@Data  //lombok注解,通过lombok构建属性的set/get方法
@TableName("ad_channel")  //标识实体类和数据库表的对应关系
public class AdChannel{

    @TableId(value = "id",type = IdType.AUTO) //标识实体类属性和数据库表主键的对应关系
    private Integer id;

    @TableField(value = "name") //标识实体类属性和数据库表字段对应关系
    private String name;

    @TableField(value = "description")
    private String description;

    @TableField(value = "is_default")
    private Boolean isDefault;

    @TableField(value = "status")
    private Boolean status;

    @TableField(value = "ord")
    private Integer ord;

    @TableField(value = "created_time")
    private Date createdTime;

}

7.4.创建mapper

@Mapper
public interface QuickStartMapper  extends BaseMapper<AdChannel> {
}

7.5.创建service接口和serviceImpl

public interface QuickStartService extends IService<AdChannel> {
}
@Service
public class QuickStartServiceImpl extends ServiceImpl<QuickStartMapper, AdChannel> implements QuickStartService {

}

7.6.修改controller代码

@RestController
@RequestMapping("/quickstart")
public class QuickStartController {

    @Autowired
    private QuickStartService quickStartService;

    @RequestMapping("/show")
    public AdChannel show(){

        AdChannel adChannel = quickStartService.getById(1);

        return adChannel;
    }

}

7.7.启动类中进行配置

@SpringBootApplication
@MapperScan("com.itheima.quickstart.mapper")
public class SpringbootQuickstartApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootQuickstartApplication.class, args);
    }


    //做分页查询的使用
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }
}

7.8.重新启动项目,重新访问项目,发现查询的就是数据库表中的数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mMqNhvjL-1626092860460)(assets/image-20210611205721137.png)]

3.开发规范

3.1.前后端分离开发

3.1.1.前后端分离开发介绍

项目基于前后端分离的架构进行开发,前后端分离架构总体上包括前端和服务端,通常是多人协作开发

  • 对于后端java工程师:

把精力放在设计模式,spring+springmvc,linux,mysql事务隔离与锁机制,mongodb,http/tcp,多线程,分布式架构,弹性计算架构,微服务架构,java性能优化,以及相关的项目管理等等。

  • 对于前端工程师:

把精力放在html5,css3,vuejs,webpack,nodejs,Google V8引擎,javascript多线程,模块化,面向切面编程,设计模式,浏览器兼容性,性能优化等等。

3.1.2.前后端分离开发流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5xNGIAxr-1626092860465)(assets/1603350582726.png)]

1,需求分析

梳理用户的需求,分析业务流程

2,接口定义

根据需求分析定义接口,定义出接口文档,具体写法可以参考资料中的接口文档目录中的《接口示例文档.md》

注意:API接口:http://localhost:8080/user/xxx 本质上就是controller的方法,所以接口文档是针对controller的方法的访问的描述(请求路径,请求参数、响应数据…)。

3,服务端和前端并行开发

服务端:依据接口文档进行服务端接口开发

前端:根据用户需求开发操作界面,并根据接口文档制作mock数据,进行测试

4,前后端集成接口联调

最终前端调用服务端接口完成业务

现在一般接口文档由后端人员来写。(接口文档一定要看看)

3.2.后端开发通用规范

3.2.1.开发原则

  • 自顶向下的设计原则:功能应该从表现层分析再到控制层、服务层、持久层逐层设计

  • 自底向上的开发原则:上层需调用下层,因此开发应从底层向上层逐层开发项目中开发的层次次序参考

    DB->中间件->持久层->服务层->控制层(controller和controller接口)(代码开发的顺序规范)

  • 单一职责的开发原则:类或者方法提供的功能应该单一明确,特别越底层越应单一职责,以便维护项目中Mapper方法必须功能单一,参数明确,拒绝两种以上的持久逻辑使用同一个Mapper方法

  • 依赖倒置的开发原则:上层依赖下层,是依赖下层接口,并不是依赖下层的实现项目中每层都是通过接口调用前端(微服务)-> Controller -> Service -> Dao(Mapper) ->DB(mysql)(项目功能测试访问顺序)

3.2.2.开发步骤

  • 明确类定义:明确哪些是重用类,哪些是需要新增的类
  • 明确主键规则:确认操作表的ID生成规则,自增或id_work
  • ControllerApi定义:定义接口
  • Mapper实现:使用mybatis-plus封装的方法还是自定义mapper映射
  • Service实现:可用通过时序图帮助我们梳理实现逻辑
  • Controller实现:简单的Service层调用
  • 单元测试或接口测试或前端直接联调测试

3.2.3.接口版本规范说明

随着业务的复杂,同一个接口可能出现多个版本,为了方便后期切换和AB测试,需要定义接口的版本号

  • 在某一个微服务下访问controller的时候在包名下加一个版本号,如下

     com.heima.article.controller.v1
    
  • 在访问具体的接口方法的url映射的时候也应该加上版本说明,如下:

     @RequestMapping("/api/v1/article")
    

扩展

AB测试:为同一个目标,设计两种方案,将两种方案随机投放市场中,让组成成分相同(相似)用户去随机体验两种方案之一,根据观测结果,判断哪个方案效果更好。

3.3.接口通用请求和响应

dto(Data Transfer Object):数据传输对象,用于展示层与服务层之间的数据传输对象,比如Result

3.3.1.通用的响应对象

不分页:com.heima.model.common.dtos.ResponseResult

/**
 * 通用的结果返回类
 * @param <T>
 */
public class ResponseResult<T> implements Serializable {

    private String host;

    private Integer code;

    private String errorMessage;

    private T data;

    public ResponseResult() {
        this.code = 200;
    }

    public ResponseResult(Integer code, T data) {
        this.code = code;
        this.data = data;
    }

    public ResponseResult(Integer code, String msg, T data) {
        this.code = code;
        this.errorMessage = msg;
        this.data = data;
    }

    public ResponseResult(Integer code, String msg) {
        this.code = code;
        this.errorMessage = msg;
    }

    public static ResponseResult errorResult(int code, String msg) {
        ResponseResult result = new ResponseResult();
        return result.error(code, msg);
    }

    public static ResponseResult okResult(int code, String msg) {
        ResponseResult result = new ResponseResult();
        return result.ok(code, null, msg);
    }

    public static ResponseResult okResult(Object data) {
        ResponseResult result = setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS,AppHttpCodeEnum.SUCCESS.getErrorMessage());
        if(data!=null) {
            result.setData(data);
        }
        return result;
    }

    public static ResponseResult errorResult(AppHttpCodeEnum enums){
        return setAppHttpCodeEnum(enums,enums.getErrorMessage());
    }

    public static ResponseResult errorResult(AppHttpCodeEnum enums,String errorMessage){
        return setAppHttpCodeEnum(enums,errorMessage);
    }

    public static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums){
        return okResult(enums.getCode(),enums.getErrorMessage());
    }

    private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums,String errorMessage){
        return okResult(enums.getCode(),errorMessage);
    }

    public ResponseResult<?> error(Integer code, String msg) {
        this.code = code;
        this.errorMessage = msg;
        return this;
    }

    public ResponseResult<?> ok(Integer code, T data) {
        this.code = code;
        this.data = data;
        return this;
    }

    public ResponseResult<?> ok(Integer code, T data, String msg) {
        this.code = code;
        this.data = data;
        this.errorMessage = msg;
        return this;
    }

    public ResponseResult<?> ok(T data) {
        this.data = data;
        return this;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }
}

分页通用返回:com.heima.model.common.dtos.PageResponseResult

public class PageResponseResult extends ResponseResult {
    private Integer currentPage;
    private Integer size;
    private Integer total;

    public PageResponseResult(Integer currentPage, Integer size, Integer total) {
        this.currentPage = currentPage;
        this.size = size;
        this.total = total;
    }

    public int getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }
}

3.3.2.通用的请求dtos

接受页面分页请求参数:com.heima.model.common.dtos.PageRequestDto

@Data
@Slf4j
public class PageRequestDto {

    protected Integer size;
    protected Integer page;

    public void checkParam() {
        if (this.page == null || this.page < 0) {
            setPage(1);
        }
        if (this.size == null || this.size < 0 || this.size > 100) {
            setSize(10);
        }
    }
}

3.3.3.通用的异常枚举

通用异常信息返回枚举:com.heima.model.common.enums.AppHttpCodeEnum

public enum AppHttpCodeEnum {

    // 成功段0
    SUCCESS(0,"操作成功"),
    // 登录段1~50
    NEED_LOGIN(1,"需要登录后操作"),
    LOGIN_PASSWORD_ERROR(2,"密码错误"),
    // TOKEN50~100
    TOKEN_INVALID(50,"无效的TOKEN"),
    TOKEN_EXPIRE(51,"TOKEN已过期"),
    TOKEN_REQUIRE(52,"TOKEN是必须的"),
    // SIGN验签 100~120
    SIGN_INVALID(100,"无效的SIGN"),
    SIG_TIMEOUT(101,"SIGN已过期"),
    // 参数错误 500~1000
    PARAM_REQUIRE(500,"缺少参数"),
    PARAM_INVALID(501,"无效参数"),
    PARAM_IMAGE_FORMAT_ERROR(502,"图片格式有误"),
    SERVER_ERROR(503,"服务器内部错误"),
    // 数据错误 1000~2000
    DATA_EXIST(1000,"数据已经存在"),
    AP_USER_DATA_NOT_EXIST(1001,"ApUser数据不存在"),
    DATA_NOT_EXIST(1002,"数据不存在"),
    // 数据错误 3000~3500
    NO_OPERATOR_AUTH(3000,"无权限操作");

    int code;
    String errorMessage;

    AppHttpCodeEnum(int code, String errorMessage){
        this.code = code;
        this.errorMessage = errorMessage;
    }

    public int getCode() {
        return code;
    }

    public String getErrorMessage() {
        return errorMessage;
    }
}

3.3.4.使用示例

在ResponseResult中的main方法中进行操作

 public static void main(String[] args) {
        //前置
        /*
        AppHttpCodeEnum success = AppHttpCodeEnum.SUCCESS;
        System.out.println(success.getCode());
        System.out.println(success.getErrorMessage());
        */

        //查询一个对象
        /*
        Map map = new HashMap();
        map.put("name","zhangsan");
        map.put("age",18);
        ResponseResult result = ResponseResult.okResult(map);
        System.out.println(JSON.toJSONString(result));
        */


        //新增,修改,删除  在项目中统一返回成功即可
        /*
        ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.SUCCESS);
        System.out.println(JSON.toJSONString(result));
        */


        //根据不用的业务返回不同的提示信息  比如:当前操作需要登录、参数错误
        /*
        ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        System.out.println(JSON.toJSONString(result));
        */

        //查询分页信息
        PageResponseResult responseResult = new PageResponseResult(1, 5, 50);
        List list = new ArrayList();
        list.add("itcast");
        list.add("itheima");
        responseResult.setData(list);
        System.out.println(JSON.toJSONString(responseResult));

}

3.4.RESTful请求风格

  • REST(Representational State Transfer),表述性状态转移,是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful。就是一种定义接口的规范。
  • 基于HTTP。
  • 可以使用XML格式定义或JSON格式定义。
  • 每一个URI代表1种资源。
  • 客户端使用GET、 POST、 PUT、 DELETE 4个表示操作方式的动词对服务端资源进行操作:
    • GET: 用来获取资源
    • POST: 用来新建资源(也可以用于更新资源)
    • PUT: 用来更新资源(也可以用于添加资源)
    • DELETE: 用来删除资源

例子:

有一个/user资源

  • get: http://localhost:8080/user/1 查询
  • delete: http://localhost:8080/user/1 删除
  • post/put: http://localhost:8080/user 添加
  • update/post:http://localhost:8080/user 修改

传统

http://localhost:8080/xxx/findAll.do?id=1

案例

@RestController
@RequestMapping("/quickstart")
public class QuickStartController {

    @Autowired
    private QuickStartService quickStartService;

    @RequestMapping("/show")
    public AdChannel show(Integer id){

        AdChannel adChannel = quickStartService.getById(id);

        return adChannel;
    }

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gZPyhaLY-1626092860466)(assets/image-20210611210903367.png)]

restful

http://localhost:8080/xxx/findAll/1

案例

@RestController
@RequestMapping("/quickstart")
public class QuickStartController {

    @Autowired
    private QuickStartService quickStartService;

    @RequestMapping("/show/{id}")
    public AdChannel show(@PathVariable("id") Integer id){

        AdChannel adChannel = quickStartService.getById(id);

        return adChannel;
    }

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M4eVuEfb-1626092860467)(assets/image-20210611211158778.png)]

3.5.多环境切换

在每一个微服务的工程中的根目录下创建三个文件,方便各个环境的切换

(1)maven_dev.properties

定义开发环境的配置

(2)maven_prod.properties

定义生产环境的配置

(3)maven_test.properties

定义测试环境的配置,开发阶段使用这个测试环境

默认加载的环境为test,在打包的过程中maven指令也可以指定参数打包: package -P test/prod/dev

具体配置,请查看父工程下的maven插件的profiles配置

<!-- maven的profile设置,主要来实现根据maven指令参数实现多环境切换 -->
<profiles>
    <profile>
        <id>dev</id>
        <build>
            <filters>
                <filter>maven_dev.properties</filter>
            </filters>
        </build>
    </profile>
    <profile>
        <id>test</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <build>
            <filters>
                <filter>maven_test.properties</filter>
            </filters>
        </build>
    </profile>
    <profile>
        <id>prod</id>
        <build>
            <filters>
                <filter>maven_prod.properties</filter>
            </filters>
        </build>
    </profile>
</profiles>

4.平台运行端(内部工作人员使用的平台)开发

4.1.频道管理

在管理平台(内部工作人员使用的管理平台)实现此功能。Admin

实际工作中功能开发的流程:分析需求 -> 开发功能 -> 简单自测

4.1.1.需求分析

整体页面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BCiGKmsI-1626092860468)(assets/1603354949253.png)]

新增弹窗

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YONeffkA-1626092860468)(assets/1603354973826.png)]

leadnews_admin管理平台(内部工作人员使用)的数据库:频道表:ad_channel

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pHbKkpgC-1626092860469)(assets/1603355081915.png)]

实体类

实体类存放位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jGn2hZIu-1626092860470)(assets/1603355214498.png)]

/**
 * <p>
 * 频道信息表
 * </p>
 *
 * @author itheima
 */
@Data  //lombok注解,通过lombok构建属性的set/get方法
@TableName("ad_channel") //表明实体类对应哪个数据库表
public class AdChannel implements Serializable {

    private static final long serialVersionUID = 1L;

    //在接口文档中作为请求参数时隐藏不显示
    //@ApiModelProperty(hidden = true)
    //表明实体类id主键字段和数据库表的主键进行映射,value:数据库表字段   type:主键id的生成策略  IdType.AUTO:自增
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 频道名称
     */
    @TableField("name") //表明实体类字段和数据库表的哪个字段映射
    private String name;

    /**
     * 频道描述
     */
    @TableField("description")
    private String description;

    /**
     * 是否默认频道
     */
    @TableField("is_default")
    private Boolean isDefault;

    @TableField("status")
    private Boolean status;

    /**
     * 默认排序
     */
    @TableField("ord")
    private Integer ord;

    /**
     * 创建时间
     */
    //@ApiModelProperty(hidden = true)
    @TableField("created_time")
    private Date createdTime;

}

4.1.2.微服务搭建

1.创建springboot功能heima-leadnews-admin

2.pom.xml文件中引入依赖

<dependencies>
        <!-- 引入依赖模块 -->
        <dependency>
            <groupId>com.heima</groupId>
            <artifactId>heima-leadnews-model</artifactId>
        </dependency>
        <dependency>
            <groupId>com.heima</groupId>
            <artifactId>heima-leadnews-common</artifactId>
        </dependency>
        <dependency>
            <groupId>com.heima</groupId>
            <artifactId>heima-leadnews-apis</artifactId>
        </dependency>
    
    
        <!-- Spring boot starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
</dependencies>

注意:其中mybatis-plus相关的依赖在heima-leadnews-model中定义 其中实体类需要mybatis-plus的注解

<dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>

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

3.创建引导类和包结构

引导类

@SpringBootApplication
public class AdminApplication {

    public static void main(String[] args) {
        SpringApplication.run(AdminApplication.class,args);
    }
}

包结构命名规范:

  • com.heima.${模块名称}为基础包名 如平台管理就是 com.heima.admin
  • config 配置信息
  • controller.v1 控制层
  • feign 需要远程调用的feign接口
  • service 业务层
  • mapper 持久层

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NQLKWGMl-1626092860471)(assets/1603355963733.png)])

4.application.yml文件配置

# 项目服务端口
server:
  port: 9001

spring:
  # 项目服务名称
  application:
    name: leadnews-admin
  # 数据库设置
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/leadnews_admin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: root
    
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
  mapper-locations: classpath*:mapper/*.xml
  # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  type-aliases-package: com.heima.model.admin.pojos

5.在引导类中增加Mybatis-plus的mapper接口扫描操作,并设置分页插件

@SpringBootApplication
@MapperScan("com.heima.admin.mapper")
public class AdminApplication {

    public static void main(String[] args) {
        SpringApplication.run(AdminApplication.class,args);
    }

    /**
     * mybatis-plus分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

6.新建日志文件:logback.xml(类似于log4j.properties)

<?xml version="1.0" encoding="UTF-8"?>

<configuration>
    <!--定义日志文件的存储地址,使用绝对路径-->
    <property name="LOG_HOME" value="E:/WorkSpace/2020WorkSpace/logs"/>

    <!-- Console 输出设置 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <!-- 按照每天生成日志文件 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <fileNamePattern>${LOG_HOME}/leadnews.%d{yyyy-MM-dd}.log</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 异步输出 -->
    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>512</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref="FILE"/>
    </appender>


    <logger name="org.apache.ibatis.cache.decorators.LoggingCache" level="DEBUG" additivity="false">
        <appender-ref ref="CONSOLE"/>
    </logger>
    <logger name="org.springframework.boot" level="debug"/>
    <root level="info">
        <!--<appender-ref ref="ASYNC"/>-->
        <appender-ref ref="FILE"/>
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

4.1.3.频道列表-接口定义

接口详情

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Ck5arwc-1626092860471)(assets/1603356704634.png)]

1.在heima-leadnews-apis模块中定义接口com.heima.api.admin.ChannelControllerApi

package com.heima.apis.admin;

import com.heima.model.admin.dtos.ChannelDto;
import com.heima.model.common.dtos.ResponseResult;

public interface AdChannelControllerApi {

    /**
     * 根据名称分页查询频道列表
     * @param dto
     * @return
     */
    public ResponseResult findByNameAndPage(ChannelDto dto);
}

2.在heima-leadnews-model模块中定义实体类ChannelDto,继承PageRequestDto

package com.heima.model.admin.dtos;

import com.heima.model.common.dtos.PageRequestDto;
import lombok.Data;

@Data
public class ChannelDto extends PageRequestDto {

    /**
     * 频道名称
     */
    private String name;
}

4.1.4.频道列表-功能实现

1.在heima-leadnews-admin中的com.heima.admin.mapper包下定义持久层接口

package com.heima.admin.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.admin.pojos.AdChannel;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface AdChannelMapper extends BaseMapper<AdChannel> {
}

2.在heima-leadnews-admin中的com.heima.admin.service包下定义业务层接口

package com.heima.admin.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.heima.model.admin.dtos.ChannelDto;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.common.dtos.ResponseResult;

public interface AdChannelService extends IService<AdChannel> {

    /**
     * 根据名称分页查询频道列表
     * @param dto
     * @return
     */
    public ResponseResult findByNameAndPage(ChannelDto dto);
}

在com.heima.admin.service.impl包下定义业务层接口实现类

package com.heima.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.service.AdChannelService;
import com.heima.model.admin.dtos.ChannelDto;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

@Service
public class AdChannelServiceImpl extends ServiceImpl<AdChannelMapper, AdChannel> implements AdChannelService {



    @Override
    public ResponseResult findByNameAndPage(ChannelDto dto) {

        //1.参数检测
        if(dto==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //分页参数检查
        dto.checkParam();

        //2.安装名称模糊分页查询
        Page page = new Page(dto.getPage(),dto.getSize());
        LambdaQueryWrapper<AdChannel> lambdaQueryWrapper = new LambdaQueryWrapper();
        if(StringUtils.isNotBlank(dto.getName())){
            // AdChannel::getName : 就是调用AdChannel中的getName()获取返回结果,再在like中使用
            lambdaQueryWrapper.like(AdChannel::getName,dto.getName());
        }
        IPage result = page(page, lambdaQueryWrapper);

        //3.结果封装
        ResponseResult responseResult = new PageResponseResult(dto.getPage(),dto.getSize(),(int)result.getTotal());
        responseResult.setData(result.getRecords());
        return responseResult;
    }
}

3.在heima-leadnews-admin中的com.heima.admin.controller.v1包中定义ChannelController,注意:ChannelController实现接口AdChannelControllerApi

@RestController
@RequestMapping("/api/v1/channel")
public class AdChannelController  implements AdChannelControllerApi {

    @Autowired
    private AdChannelService channelService;

    @PostMapping("/list")
    @Override
    public ResponseResult findByNameAndPage(@RequestBody ChannelDto dto){
        return channelService.findByNameAndPage(dto);
    }
}

4.2.接口测试工具

启动heima-leadnews-admin项目,进行测试。

注意事项

注意1

在install工程的时候,会出现heima-leadnews-admin工程install失败,这个不要紧,因为heima-leadnews-admin是要启动起来作为web项目存在的,所以不用install也可以。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wdwGosEj-1626092860472)(assets/1603360918148.png)]

启动heima-leadnews-admin出现以下信息,不是启动失败

4.2.1.接口测试工具-postman

主要用于后端人员进行后端代码测试

1.简介

Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。**postman被500万开发者和超100,000家公司用于每月访问1.3亿个API。**java开发通常是作为后台开发语言,通常的项目中的接口开发需要一款测试工具来调试接口,这样无需前端页面也不耽误后台代码的开发进度,postman作为一个接口测试工具,是一个非常不错的选择。

官方网址:https://www.postman.com/

2.安装

解压资料文件夹中的软件,安装即可。

3.请求和响应

请求方式选择

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i9NfHwEN-1626092860473)(assets/1603361677447.png)]

url输入,并发送请求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cw40eO7O-1626092860474)(assets/1603361713084.png)]

json请求参数的设置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ALK0lw0g-1626092860475)(assets/1603361736425.png)]

整体设置,并发送请求,获取响应数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b1w2kPyb-1626092860476)(assets/1603361613754.png)]

4.3.频道管理后续功能实现

4.3.1.频道管理-新增

后台开发流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zMSy7aEW-1626092860477)(assets/1603371695414.png)]

1.在heima-leadnews-apis的AdChannelControllerApi中增加接口

/**
 * 新增
 * @param channel
 * @return
 */
public ResponseResult save(AdChannel channel);

2.在heima-leadnews-admin的ChannelController中实现接口方法

/**
 * 新增
 * @param channel
 * @return
 */
@Override
@PostMapping("/save")
public ResponseResult save(@RequestBody AdChannel channel) {
  return channelService.insert(channel);
}

3.在heima-leadnews-admin的AdChannelService中增加接口

/**
 * 新增
 * @param channel
 * @return
 */
public ResponseResult insert(AdChannel channel);

4.在heima-leadnews-admin的AdChannelServiceImpl中实现接口方法

/**
     * 新增
     * @param adChannel
     * @return
     */
    @Override
    public ResponseResult insert(AdChannel adChannel) {
        //1.检查参数
        if(null == adChannel){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2.保存
        adChannel.setCreatedTime(new Date());
        save(adChannel);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

5.启动项目测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qPnBpZbA-1626092860478)(assets/1603373596290.png)]

4.3.2.频道管理-修改

需求分析

有效无效状态修改

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dOJ3FjTY-1626092860479)(assets/1603373845313.png)]

编辑内容

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2UA5ktD5-1626092860480)(assets/1603373886648.png)]

1.在heima-leadnews-apis的AdChannelControllerApi中增加接口

 /**
     * 修改
     * @param adChannel
     * @return
     */
    public ResponseResult update(AdChannel adChannel);

2.在heima-leadnews-admin的ChannelController中实现接口方法

/**
     * 修改
     */
    @Override
    @PostMapping("/update")
    public ResponseResult update(@RequestBody AdChannel adChannel) {
        return channelService.update(adChannel);
    }

3.在heima-leadnews-admin的AdChannelService中增加接口

/**
     * 修改
     * @param adChannel
     * @return
     */
    public ResponseResult update(AdChannel adChannel);

4.在heima-leadnews-admin的AdChannelServiceImpl中实现接口方法

/**
     * 修改
     * @param adChannel
     * @return
     */
    @Override
    public ResponseResult update(AdChannel adChannel) {

        //1.检查参数
        if(null == adChannel || adChannel.getId()==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2.修改
        updateById(adChannel);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

5.启动项目测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-133TcaZC-1626092860481)(assets/1603374229582.png)]

4.3.3.频道管理-删除

需求分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HyeWvd5x-1626092860481)(assets/1603374288342.png)]

注意:如果当前状态为有效则不能删除

1.在heima-leadnews-apis的AdChannelControllerApi中增加接口

/**
     * 删除
     * @param id
     * @return
     */
    public ResponseResult deleteById(Integer id);

2.在heima-leadnews-admin的ChannelController中实现接口方法

/**
     * 删除
     * @param id
     * @return
     */
    @Override
    @GetMapping("/del/{id}")
    public ResponseResult deleteById(@PathVariable("id") Integer id) {
        return channelService.deleteById(id);
    }

3.在heima-leadnews-admin的AdChannelService中增加接口

 /**
     * 删除
     * @param id
     * @return
     */
    public ResponseResult deleteById(Integer id);

4.在heima-leadnews-admin的AdChannelServiceImpl中实现接口方法

/**
     * 删除
     * @param id
     * @return
     */
    @Override
    public ResponseResult deleteById(Integer id) {
        //1.检查参数
        if(id == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2.判断当前频道是否存在 和 是否有效
        AdChannel adChannel = getById(id);
        if(adChannel==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        if(adChannel.getStatus()){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"频道有效不能删除");
        }

        //int i = 10/0;

        //3.删除频道
        removeById(id);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

5.启动项目测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TigZPeYP-1626092860482)(assets/1603374945869.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j7UoAwJb-1626092860483)(assets/1603374973463.png)]

 类似资料: