前后端分离模式:springboot+beetlsql+swagger高效开发利器

         目前主流的公司和开发团队都比较关注前后端分离模式的开发。该模式明确了前后端的作用和职责,一定程度上降低了前后端人员的开发时间成本,但是技术却有一定的要求。前后端分离模式极大解耦了前后端服务的关系,避免了前端严重依赖后端,解决了前后端接口交互不及时,易变更等问题。使得前后端开发人员能更高效的专注自己的领域。

         前后端分离后,关键的桥梁就是接口。通过接口将前后端联系在一起。而接口交互一直以来是前后端人员交互容易产生冲突的地方。而随着swagger等接口信息自动化生成测试的技术出现,极大减少了这种冲突。swagger由后端开发人员集成到项目中,使用相应的注解来描述接口,参数,返回模型等各类信息。后端开发人员如果变更了接口,接口可以及时反映到前端。

         首先一个springboot项目集成swagger需要依赖以下包:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>${version.swagger}</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>${version.swagger}</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-bean-validators</artifactId>
    <version>${version.swagger}</version>
</dependency><dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

       将以上版本改为自己使用的版本即可,引入依赖包后还需要将swagger整合到项目中,整合后在启动类加上注解即可。swagger整合到springboot中网上有很多相关资料,这里不再贴出代码。本人的swagger整合和网上不同,本人将swagger中的核心类进行了重构,开发了自己的注解,采用配置的方式整合。如下:

@EnableAutoSwagger2
@SpringBootApplication(scanBasePackages = {"com.yougu.core","com.yougu.server.common"})
public class ServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args);
    }
}

 

## Swagger configuration
swagger:
  enabled: true
  title: ${info.build.name}
  description: ${info.build.description}
  version: ${info.build.version}
  base-package: com.yougu.core
  base-path: /**

     需要注意@EnableAutoSwagger2不能直接用,是本人自己开发的注解。这里给出思路,大家可以根据自己的情况也进行相应的重构。swagger的效果在下面结合代码给出图片。

      beetlsql的使用比mybatis效率有很大的提升。遵循约定优于配置的原则,这正好和springboot的理念相符。beetlsql通过反射机制,将数据库的表结构和对应的javabean直接进行关联,大大减少开发人员的无关配置。开发效率得到了很大提升。在springboot中引入beetlsql,这里以mysql数据库为例:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>com.ibeetl</groupId>
    <artifactId>beetl</artifactId>
</dependency>
<dependency>
    <groupId>com.ibeetl</groupId>
    <artifactId>beetlsql</artifactId>
</dependency>

     由于本人代码对数据库连接做了多数据源和工具的重构,这里也不在贴出整合代码, 网上可自行查找相关简单的集成。下面只给出数据库的配置:

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/csic_722_mis?useunicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: xxxx
    password: xxxxx
    sql-root: /sql
    dao-suffix: Repository
    product-mode: false
    offset-start-zero: true
    debug-interceptor: true
    base-package: com.yougu.core.repository
    druid:
      enable: true
      initial-size: 5
      min-idle: 8
      max-active: 15
      connection-init-sqls: 'SET NAMES utf8mb4'
      validation-query: 'SELECT 1'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      pool-prepared-statements: true
      max-open-prepared-statements: 20
      use-global-data-source-stat: true
      filters: stat,slf4j,wall,config
      stat-view-servlet:
        enabled: true
        url-pattern: /druid/*
        reset-enable: true       

    下面结合具体的例子来说明该模式的开发。

     首先将前后端的交互接口进行抽象,抽象成一个接口对象,而不提供具体实现,然后由Controller进行具体的实现,抽象的接口使用swagger注解对接口进行描述,Controller中只需实现接口,避免代码直接污染Controller

@Api(value = "dept Api Client", description = "部门-API(幽谷)", protocols = "application/json")
public interface DeptApi {
    String BASE_PATH = "/server/dept";

    @ApiOperation(value = "通过ID查询部门信息 #幽谷/2019-05-03#", notes = "通过ID查询部门信息", nickname = "dept-get")
    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "查询对象", paramType = "path", dataType = "int", required = true)})
    @RequestMapping(value = BASE_PATH + "/get/{id}" ,method = RequestMethod.GET)
    DeptDto get(@PathVariable("id") int id);

    @ApiOperation(value = "通过条件分页查询部门信息 #幽谷/2019-05-03#", notes = "通过条件分页查询部门信息", nickname = "dept-pageDept")
    @ApiImplicitParams({@ApiImplicitParam(name = "deptParamDto", value = "查询对象", paramType = "body", dataType = "DeptParamDto", required = true)})
    @RequestMapping(value = BASE_PATH + "/pageDept" ,method = RequestMethod.POST)
    PageData<DeptDto> pageDept(@RequestBody DeptParamDto deptParamDto);

    @ApiOperation(value = "新增部门信息 #幽谷/2019-05-03#", notes = "新增部门信息", nickname = "dept-create")
    @ApiImplicitParams({@ApiImplicitParam(name = "deptInsertDto", value = "新增部门对象", paramType = "body", dataType = "DeptInsertDto", required = true)})
    @RequestMapping(value = BASE_PATH + "/create" ,method = RequestMethod.POST)
    String create(@RequestBody DeptInsertDto deptInsertDto);

    @ApiOperation(value = "修改部门信息 #幽谷/2019-05-03#", notes = "修改部门信息", nickname = "dept-update")
    @ApiImplicitParams({@ApiImplicitParam(name = "deptModifyDto", value = "修改部门对象", paramType = "body", dataType = "DeptModifyDto", required = true)})
    @RequestMapping(value = BASE_PATH + "/update" ,method = RequestMethod.POST)
    String update(@RequestBody DeptModifyDto deptModifyDto);

    @ApiOperation(value = "删除部门信息 #幽谷/2019-05-03#", notes = "删除部门信息", nickname = "dept-delete")
    @ApiImplicitParams({@ApiImplicitParam(name = "idsDto", value = "删除部门ID集", paramType = "body", dataType = "IdsDto", required = true)})
    @RequestMapping(value = BASE_PATH + "/delete" ,method = RequestMethod.POST)
    String delete(@RequestBody IdsDto idsDto);
}

          由于代码较多,下面只贴出删除方法的实现:

@Override
public String delete(@RequestBody IdsDto idsDto) {
    DeptUnit deptUnit = new DeptUnit();
    deptUnit.setUpdatedAt(LocalDateTime.now());
    deptUnit.setUpdatedBy(MyRequestContextHolder.getUserId());
    deptUnit.setDelFlag(Boolean.TRUE);
//代码尽量避免罗嗦,该行代码至少将5个操作融为一体,1、三目运算2、字符串截取3、字符串转字符串数组4、字符串数组转字符串集合5、字符串集合转整型集合
    List<Integer> idList = commonMapper.toIntList(
            Arrays.asList(
                    StringUtils.commaDelimitedListToStringArray(
                            idsDto.getIds().endsWith(",")?idsDto.getIds().substring(0,idsDto.getIds().length() - 1):idsDto.getIds())));
    if(!ObjectUtils.isEmpty(idList))//java的开发在于使用具体,而不是重复造轮子,也尽量自己少写if(null == obj),可以直接使用工具类。
        repository.myDeleteByIds( idList, deptUnit);
    return CommonConstant.DELETE_SUCCESS_MSG;
}

 下面是使用beetlsql的dao层

@Component
@SqlResource("dept")
public interface DeptRepository extends BaseMapper<DeptUnit> {
    void pageDept(PageQuery<DeptDto> pageQuery);

    int myDeleteByIds(@Param("idList") List<Integer> idList, @Param("deptUnit") DeptUnit deptUnit);
}

sql文件则只需要写sql语句,不需要进行数据结构配置

myDeleteByIds
===
*根据ID批量软删除信息

    UPDATE 
        csic_mis_dept
    SET 
        del_flag = #deptUnit.delFlag#,updated_At = #deptUnit.updatedAt#,updated_By = #deptUnit.updatedBy#
    WHERE
        id IN (#join(idList)#)

 beetlsql更强大的地方在于其已经自动生成了大量基础sql,对于上面四个接口,只需写两个sql即足够,比如查询,无需写sql,可以直接引用:

@Override
public DeptDto get(@PathVariable("id") int id) {
    return mapper.toDeptDto(repository.createQuery().andEq("id", id).andEq("del_flag", Boolean.FALSE).select());
}

一句代码解决该服务,是不是开发效率大大提升。

 前端只需要更具swagger生成的接口图进行调用和测试即可:

     通过swagger可以直接明了的查看接口信息,数据模型,字段属性等。 

     以上即是一个简单的后端模式开发过程。后端开发往往较为复杂,使用一个好的架构模式,可以很好的提升开发效率,减少不必要的麻烦。后续再给出后端开发的其他架构设计。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值