A063_后端搭建_Lombok_Restful_postman_swagger


项目搭建

内容介绍

1. 项目介绍; (了解)
2. 需求分析; (了解)
3. 项目架构; (掌握)
4. 后端项目搭建; (掌握)
5. swagger (掌握)
6. postman测试 (掌握)

需求分析 需求设计(项目架构)开发 测试 上线

1.项目介绍

  • 本项目是一个(Online To Offline)以宠物为核心打造的宠物乐园o2o项目。随着生活质量提供,人们不再满足简单物质生活,还追求更高层次精神生活。很多人愿意有养宠物意愿,愿意为宠物消费,正是基于这种场景,我们才开发了这个项目。首先让用户领养宠物,然后针对用户的宠物提供上门洗澡,美容,寄养,购买商品,宠物百科等综合服务平台。由用户下单,平台统一分派给线下门店上门服务。平台除了提供针对普通用户的基本需求功能,支持商家入驻,合作加盟,扩展线下门店渠道。

  • O2o:通过互联网手段挖掘机会,最终要到线下消费。

    汽车之家 房屋之家 育儿 婚恋等

2.需求分析

在这里插入图片描述

3.项目架构

3.1.项目技术架构

在这里插入图片描述

后端架构:		springboot+ ssm+ 
				echart+ quartz+
				Javaemail+ 
				Easypoi+redis

前端架构:        vue技术栈:nodejs npm webpack vue vue-cli elementui

服务器:        linux+nginx+docker
数据存储:        mysql +redis+fastdfs
第三方登录      微信 微博 QQ
第三方支付      支付宝扫描支付
第三方短信接口  中国网建

今天:后端项目搭建
明天:前后端整合
3.2.前后端分离
3.2.1. 什么是前后端分离

在传统的web应用开发中,大多数的程序员会将浏览器作为前后端的分界线。将浏览器中为用户进行页面展示的部分称之为前端,而将运行在服务器,为前端提供业务逻辑和数据准备的所有代码统称为后端。
很多人误以为前后端分离只是一种web应用开发模式,只要在web应用的开发期进行了前后端开发工作的分工就是前后端分离。 前后端分工
其实前后端分离并不只是开发模式,而是web应用的一种架构模式。在开发阶段,前后端工程师约定好数据交互接口,实现并行架构,开发和测试;在运行阶段前后端分离模式需要对web应用进行分别部署,前后端之前使用HTTP或者其他协议进行交互请求。然而作为一种架构模式,我们在实施的过程中主要对以下四个方面来进行比较和重新认识。

前后端分离大概可以从以下方面来理解:

3.2.2.交互形式

在这里插入图片描述
在前后端分离架构中,后端只需要负责按照约定的数据格式向前端提供可调用的API服务即可。前后端之间通过HTTP请求进行交互,前端获取到数据后,进行页面的组装和渲染,页面跳转,最终返回给浏览器。

3.2.3.代码组织方式

在这里插入图片描述
在传统架构模式中,前后端代码存放于同一个代码库中,甚至是同一工程目录下。页面中还夹杂着后端代码。前后端工程师进行开发时,都必须把整个项目导入到开发工具中。而前后端分离模式在代码组织形式上有以下两种:

半分离
前后端共用一个代码库,但是代码分别存放在两个工程中。后端不关心或很少 关心前端元素的输出情况,前端不能独立进行开发和测试,项目中缺乏前后端 交互的测试用例。

真分离
前后端代码库分离,前端代码中有可以进行Mock测试(通过构造虚拟测试对 象以简化测试环境的方法)的伪后端,能支持前端的独立开发和测试。而后端 代码中除了功能实现外,还有着详细的测试用例,以保证API的可用性,降低 集成风险。

3.3.前后端分离开发模式
3.3.1.真正前后端分离

在这里插入图片描述
能力要求高,大公司

3.3.2.后端先行

在这里插入图片描述
能力要求低,小公司,刚转型前后端分离的公司

前后端分离全栈项目

3.4.前后端分离优缺点

优点:
分工明确,专业的人做专业的事情。
专业可以做出炫丽优美界面
人员培养更加专业化,精确化
缺点:
成本提高,人员多。
项目管理难度也提高,前后端都要管,协调他们之间交流。

它是趋势,移动互联要求必须有移动端,需要专业前端人员,好多公司都做前后端分离。

4.后端项目搭建

4.1.项目规划

在这里插入图片描述

项目端口规划
后台接口服务8080
后台管理前端8081
门户网站前端80

所有的人都不能用cn.itsource的包名,org/cn.姓名英文

4.2.Idea配置maven

在这里插入图片描述

4.3.整合springboot环境

在这里插入图片描述

1)创建maven项目-用自己的包名
2)Pom 配置父亲

	<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
    </parent>

    <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>
        </dependency>
    </dependencies>

3)application.yml

server:
  port: 8080

4)入口类

package cn.itsource;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

5)启动测试
启动测试

4.4.Ssm Crud

Pom.xml 配置文件 入口列 domain maper.java mapper.xml service/impl test controller

4.4.1.pom.xml
<!-- spring-boot整合mybatis -->
		<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
4.4.2.配置文件

application.yml

server:
  port: 8081
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: 0731javaroot
    url: jdbc:mysql://localhost:3306/pethome?useUnicode=true&characterEncoding=UTF-8
mybatis:
  type-aliases-package: cn.itsource.org.domain,cn.itsource.org.query,

准备库和表
入口类打扫描Mapper的标签
@MapperScan(“cn.itsource.*.mapper”)

4.4.3.创建部门domain
public class Department {
    /*主键*/
    private Long id;
    /*部门编号*/
    private String sn;
    /*部门名称*/
    private String name;
    /*暂时不用*/
    private String dirPath;
    /*部门状态 0 正常 ,-1 停用*/
    private int state;
    /*部门经理 和员工关联*/
    //private String manager;
    /*上级部门
    private Department parent;
    private List<Department> children = new ArrayList<>();
*/
}
4.4.4. Lombok

在开发中每个类都需要写getter与setter方法,以及覆写toString。Lombok插件可以让开发中省略这部分重复的工作。

4.4.4.1. 引入相关jar包
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok 
   导入这个jar后,编译后会自动生成相关方法
-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
    <scope>provided</scope>
</dependency>

4.4.4.2.IDEA添加插件对于Lombok的支持-编码时也支持

在这里插入图片描述
安装完成以后需要重启idea。

4.4.4.3.常用注解

官方文档:https://projectlombok.org/features/all
在这里插入图片描述

其中@Data注解最常用,标注于类之上,是@ToString,@EqualsAndHashCode、@Getter、@Setter、@RequiredArgsConstructor的综合体。

4.4.5.Mapper接口
public interface DepartmentMapper {
    //基础查询
    void save(Department d);

    void remove(Long id);

    void update(Department d);

    Department loadById(Long id );

    List<Department> loadAll();

    /**
     * 分页查询
     *
     */
    //查询总条数
    Long queryCount(DepartmentQuery query);
    //查询当前的页数
    List<Department> queryData(DepartmentQuery query);
    
}

注意:DepartmentQuery 为Department的查询查询类,其中包括分页数据,以及关键字查询。

4.4.6.DepartmentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="cn.itsource.org.mapper.DepartmentMapper">
    <!--//保存对象-->
    <!--void save(Department department);-->
    <insert id="save" parameterType="Department">
        insert into t_department(
            sn,
            name,
            dirPath,
            state,
            manager_id,
            parent_id

        )values(
            #{sn},
            #{name},
            #{dirPath},
            #{state},
            #{manager.id},
            #{parent.id}

        )


    </insert>

    <!--//移除一个对象-->
    <!--void remove(Long id);-->
    <delete id="remove" parameterType="long">
        delete from t_department where id = #{id}
    </delete>

    <!--//更新一个对象-->
    <!--void update(Department department);-->
    <update id="update" parameterType="Department">
        update t_department set
            sn=#{sn},
            name=#{name},
            dirPath=#{dirPath},
            state=#{state},
            manager_id=#{manager.id},
            parent_id=#{parent.id}
        where id = #{id}

    </update>

    <!--//加载一个对象-->
    <!--Department loadById(Long id);-->
    <select id="loadById" parameterType="long" resultType="Department">
          select * from t_department where id = #{id}
    </select>
    <!--//加载所有对象-->
    <!--List<Department> loadAll();-->
    <select id="loadAll" resultType="Department">
        select * from t_department
    </select>

    <!--//分页相关的,查询总数,查询当前页数据-->
    <!--Long queryCount(DepartmentQuery query);-->
    <select id="queryCount" parameterType="DepartmentQuery" resultType="long">
        select count(*) from t_department
    </select>
    <!--List<Department> queryData(DepartmentQuery query);-->
    <select id="queryData" parameterType="DepartmentQuery" resultType="Department">
        select * from t_department
        limit #{start},#{pageSize}
    </select>

</mapper>
4.4.7.Service
public interface IDepartmentService {
    void add(Department d);

    void upadte(Department d);

    void del(Long id );

    Department getById(Long id );

    List<Department> getAll();

    /*
     分页查询
     */
    PageList<Department> queryData(DepartmentQuery query);
}

PageList 页面返回的数据:

/**
 * 分页以后给页面返回的数据
 * @param <T>
 */
public class PageList<T> {
    //总条数
    private Long tatal=0L;
    //页面展示的数据
    private List<T> rows = new ArrayList<>();

    public PageList() {
    }

    public PageList(Long tatal, List<T> rows) {
        this.tatal = tatal;
        this.rows = rows;
    }
}

实现类代码:

@Service
//类级别事务为读事务,分别在增删改的方法上面加写事务
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
public class DepartmentServiceImpl implements IDepartmentService {
    @Autowired
    private DepartmentMapper departmentMapper;
    @Override
    @Transactional
    public void add(Department d) {
        departmentMapper.save(d);

    }

    @Override
    @Transactional
    public void upadte(Department d) {
        departmentMapper.update(d);

    }

    @Override
    @Transactional
    public void del(Long id) {
        departmentMapper.remove(id);

    }

    @Override
    public Department getById(Long id) {
        return departmentMapper.loadById(id);
    }

    @Override
    public List<Department> getAll() {
        return departmentMapper.loadAll();
    }

    @Override
    public PageList<Department> queryData(DepartmentQuery query) {
        Long total = departmentMapper.queryCount(query);
        if (total==null || total.intValue()<1){
            return new PageList<>();
        }
        List<Department> list = departmentMapper.queryData(query);

        return new PageList<>(total,list);
    }
}
4.4.8.测试

在这里插入图片描述
在这里插入图片描述

4.4.9.Controller
 见4.5
4.5.Controller
4.5.1.什么是Restful风格

Restful是一种面向资源的架构风格,可以简单理解为:使用URL定位资源,用HTTP动词(GET,POST,DELETE,PUT,PATCH(批量操作))描述操作。

get 	http://127.0.0.1:8080/user/1 	获取用户
delete 	http://127.0.0.1:8080/user/1 	删除用户
put 	http://127.0.0.1:8080/user/  	修改用户
{
   Id:1
    Name:zs
}
Post	 http://127.0.0.1:8080/user/ 	添加用户
{
   Name:zs
}
4.5.2.Restful好处
  1. 拥有http的优点
    本身就是http,无状态,不用关心两次访问上下文.
  2. 透明性,暴露资源存在
    看到命令就知道要做什么了
  3. 充分利用 HTTP 协议本身语义。
    原来只用get,post,现在连delete和put
4.5.3.特征
  1. 资源使用名词表示
    资源是通过url描述,也就是在url不要出现动词

  2. 使用http动词来描述操作
    get 获取 post新增 put修改 delete删除 patch批量操作

    json:数据传输方式之一
    对象:{}
    数组:[{},{}]

4.5.4.Controller实现
@GetMapping("xx")
@PostMapping("xx")
@DeleteMapping
@PutMapping
@RequestMapping(value = "xx",method = RequestMethod.POST)
package cn.itsource.org.controller;
import cn.itsource.basic.util.AjaxResult;
import cn.itsource.basic.util.PageList;
import cn.itsource.org.domain.Department;
import cn.itsource.org.query.DepartmentQuery;
import cn.itsource.org.service.IDepartmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController //@Controller+@ResponseBody(转换json)
@RequestMapping("/department")
public class DepartmentController {

    @Autowired
    private IDepartmentService departmentService;

    //传对象就用@RequestBody
    @PutMapping //添加或修改
    public AjaxResult addOrUpdate(@RequestBody Department department) {

        try {
            if (department.getId() != null) {
                departmentService.update(department);
            } else {
                departmentService.add(department);
            }

            return AjaxResult.me();
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.me().setSuccess(false).setMessage("保存失败!" + e.getMessage());
        }

    }


    @DeleteMapping("/{id}") // /department/1
    public AjaxResult delete(@PathVariable("id") Long id) {
        try {
            departmentService.delete(id);
            return AjaxResult.me();
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.me().setSuccess(false).setMessage("删除失败!" + e.getMessage());
        }
    }


    @GetMapping("/{id}")
    public Department get(@PathVariable("id") Long id){
        return departmentService.getById(id);
    }


    @GetMapping
    public List<Department> getAll(){
        return departmentService.getAll();
    }

    //axios get不支持传对象
    @PostMapping
    public PageList<Department> list(@RequestBody DepartmentQuery query){

        return departmentService.queryPage(query);
    }



}

AjaxResult :前台调用返回的数据

**
 * 有些controller的操作以后的返回,只关心成功与否,以及失败了的原因
 *  而且应该返回值是json数据。 {success:true/false,message:"系统错误“,resultObj:{}}
 *  方案1; 后台拼接字符串返回 太麻烦,代码可读性差
 *  方案2: 其实可以使用spirngmvc的自动转换json的功能
 *        第一步:封装对象
 *       封装一个对象,里面有两个属性 success ,message
 *       到时候我构造一个对象返回,spirngmvc会自动帮我转换。
 *       第二步:默认构造函数
 *
     *  //成功的时候调用
     public AjaxResult() {
     }

     //失败的时候调用
     public AjaxResult(String message) {
     this.success = false;
     this.message = message;

       //第三步:配置链式编程

      //第四步:除了成功与否,还需要带一些额外数据到前台
 }
 */
@Data
public class AjaxResult {

    private boolean success = true;
    private String message = "操作成功!";

    private Object resultObj;
    private Serializable sessionId;

    public boolean isSuccess() {
        return success;
    }

    //链式编程,可以继续. 设置完成后自己对象返回
    public AjaxResult setSuccess(boolean success) {
        this.success = success;
        return this;
}

    public AjaxResult setResultObj(Object resultObj){
        this.resultObj = resultObj;
        return  this;
    }

    public String getMessage() {
        return message;
    }

    public AjaxResult setMessage(String message) {
        this.message = message;
        return this;
    }

    //默认成功
    public AjaxResult() {
    }

    //失败调用
    public AjaxResult(String message) {
        this.success = false;
        this.message = message;
    }

    //不要让我创建太多对象
    public static AjaxResult me(){
        return new AjaxResult();
    }

    public static void main(String[] args) {
        AjaxResult.me().setMessage("xxx").setSuccess(false);
    }
}

如果是get请求还可以通过浏览器测试,但是其他请求就不行了。

4.6.Postman接口测试

我们基于springmvc写的controller对于前端来说就是接口,而且都是通过http协议访问,那后台写完后怎么测试呢?浏览器,只支持get。 要使用一些能够发送http各种请求的工具,其中postman就是很重要的一个。

4.6.1.什么是postman

就是一个工具,可以来发送各种http请求,可以用它来测试http协议接口.
postman就是httm协议接口测试工具

4.6.2.入门
4.6.2.1.下载安装

略过

4.6.2.2.注册和登录

略过

64009120@qq.com / hmtest123/hmtest123

4.6.2.3.测试crud接口

在这里插入图片描述

查询所有
在这里插入图片描述

添加
在这里插入图片描述

删除
略过

修改
在这里插入图片描述

4.7.接口规范swagger
4.7.1.为什么需要

1)接口测试人员要通过接口描述测试接口 --黑盒测试
2)前端开发人员要通过接口描述使用接口.

测试 怎么测试接口
前端人员 后端人员

怎么描述???
1)写接口doc文档
直接罗列所有接口,每个接口有访问地址(访问方式),参数及返回值.
2)可以直接通过后端代码产生能够让前台开发或测试人员能够看懂就ok—swagger文档 json,yml,页面展示 采纳

4.7.2.实现

添加swagger的jar包:

        <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>

添加配置类:

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                //对外暴露服务的包,以controller的方式暴露,所以就是controller的包.
                .apis(RequestHandlerSelectors.basePackage("cn.itsource"))
                .paths(PathSelectors.any())
                .build();
    }


    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("系统中心api")
                .description("系统中心服务接口文档说明")
                .contact(new Contact("hmtest", "", "hm@itsource.cn"))
                .version("1.0")
                .build();
    }
}

4.7.3.访问接口规范

地址:http://localhost:8080/swagger-ui.html
在这里插入图片描述

@RestController //@Controller+@ResponseBody(转换json)
@RequestMapping("/department")
@Api(tags = "部门接口",description = "部门接口详细描述")
public class DepartmentController {

    @Autowired
    private IDepartmentService departmentService;

    @ApiOperation(value = "部门添加或修改",notes = "如果有id就是修改否则就是添加")
    //传对象就用@RequestBody
    @PutMapping //添加或修改

4.8.小结

按照restfull规范写一个一个crud接口,通过postman来做接口测试,通过swagger来描述接口.

5.课程总结

5.1.重点

1.Mybatis的基本CRUD
2.Restful风格

5.2.难点

1.抽取

5.3.如何掌握
5.4.排错技巧(技巧)

6.常见问题

7.课后练习

1.完成当日代码

8.面试题

9.扩展知识或课外阅读推荐(可选)

9.1.扩展知识
9.2.课外阅读
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值