Spring Boot学习笔记(六)结合MyBatis实现较为复杂的RESTful API

前两篇已经构建了RESTful API标准工程实例,也整合了MyBatis实现了简单数据库访问,本篇主要更深入的学习下,实现较为完整的数据库CRUD的标准服务。

首先看下要实现的效果吧,完成下面截图部分的API,除了CRUD之外,分页查询也是使用的比较多的。

image

这次是采用代码编写的方式,没有使用通用mapper和分页组件,打算先熟悉下整个流程,后面实际开发功能的话还是使用的好,提高开发效率。

下面是编码的详细步骤:

编写TempMapper

我们优先实现数据库访问,之前一直采用的是注解的方式,所以这次就注解到底了。

但是遇到了第一个问题,sql如何拼接,之前简单的例子不会涉及,但这次有分页,有更新(可能更新某个字段)。

网上看了下,一种方式是使用<script>方法动态去拼接,尝试了一下,发现这代码可读性太差了,还不如直接用xml的方式了,后来才知道有@Provider,动态语言注解,其实就是通过该注解去指向你生成动态Sql的方法,相关代码如下:

我们定义一个TempSqlProvider类,用于提供所需要的Sql字符串,这里写了两个方法,分别生成分页查询的sql语句和更新sql语句:

public class TempSqlProvider {
    //生成分页Sql
    public String sqlTempPaging(Map<String, Object> map)
    {
        StringBuffer sql = new StringBuffer("select id,name,content from temp where 1=1 ");
        if(map.get("id")!=null)
        {
            sql.append(" and id=#{id}");
        }
        if(map.get("name")!=null)
        {
            sql.append(" and name=#{name}");
        }
        if(map.get("content")!=null)
        {
            sql.append(" and content=#{content}");
        }
        if(map.get("offect")!=null&&map.get("limit")!=null)
        {
            sql.append(" limit #{offset}, #{limit}");
        }
        return sql.toString();
    }
    
    //生成更新Sql
    public String updateTempSql(Temp temp)
    {
        return new SQL(){{
            UPDATE("temp");

            if(temp.getName() != null){
                SET("name=#{name}");
            }
            if(temp.getContent() != null){
                SET("content=#{content}");
            }
            WHERE("id=#{id}");
        }}.toString();
    }
}

可以看到,这里用了两种方式,查询的sql我通过字符串拼接的方式直接写sql,而更新的sql我使用MyBatis提供了SQL类org.apache.ibatis.jdbc.SQL,大家可以参考下,后者看起来更优雅点。

然后我们可以编写TempMapper了,具体代码如下:

@Mapper
public interface TempMapper {

    @Select("SELECT `id`,`name`,`content` FROM TEMP WHERE ID = #{id}")
    Temp findById(@Param("id") Integer id);

    @SelectProvider(type=TempSqlProvider.class,method="sqlTempPaging")
    List<Temp> getTempPaging(Map<String, Object> map);

    @Insert("INSERT INTO TEMP(NAME, CONTENT) VALUES(#{name}, #{content})")
    int insert(@Param("name") String name,@Param("content") String content);

    @UpdateProvider(type=TempSqlProvider.class,method="updateTempSql")
    int update(Temp temp);

    @Delete("DELETE FROM TEMP WHERE ID=#{id}")
    int delete(@Param("id") Integer id);
}

这里可以看到,我们分别通过@SelectProvider@UpdateProvider注解,指向对应sql的类和方法,实现动态sql。

到这里,最复杂的数据访问基本就算编写完了。

轻插:MyBatis的一些注解说明

除了常规的CRUD的注解之外(@Select,@Update,@Insert,@Delete)和使用动态语言注解@Provider之外,有必要再说明下传参方式。

使用@Parm

基本上有三种,在上面的demo都有使用到findById方法,@Parm中定义的id对应sql中#{id}

使用Map

当参数过多且不确定时,通过Map对象来作为传递参数的容器,如上面getTempPaging方法,但是在代码可读性上比较差点,我只有到具体sql中才能找到具体有哪些参数。

使用对象

使用普通的java对象来作为传参方式,如上面的update方法,当参数确定时使用对象的方式比较好。

编写Service层

我们继续编写Service层。

首先定义TempService接口,确认给要输出的方法,代码如下,简单的CRUD和一个分页的查询方法:

public interface TempService {
    Temp getTemp(Integer id);
    List<Temp> getTempPaging(Map<String, Object> map);
    Boolean insertTemp(Temp temp);
    Boolean updateTemp(Temp entity);
    Boolean deleteTemp(Integer id);
}

然后编写对应实现TempServiceImpl,代码如下:

@Service
public class TempServiceImpl implements TempService{

    @Autowired
    private TempMapper tempMapper;

    @Override
    public Temp getTemp(Integer id)
    {
        return tempMapper.findById(id);
    }

    @Override
    public List<Temp> getTempPaging(Map<String, Object> map)
    {
        return tempMapper.getTempPaging(map);
    }

    @Override
    public Boolean insertTemp(Temp temp)
    {
        return tempMapper.insert(temp.getName(),temp.getContent())>0;
    }

    @Override
    public Boolean updateTemp(Temp entity)
    {
        return tempMapper.update(entity)>0;
    }

    @Override
    public Boolean deleteTemp(Integer id)
    {
        return tempMapper.delete(id)>0;
    }
}

这部分没有什么好说的,由于没有很复杂的逻辑,直接调用的mapper。

编写Controller

暴露对外访问路由,同时整合Swagger,整体代码如下:

@Api(description ="Temp测试服务")
@RestController
@RequestMapping("/temp")
public class TempController {
    @Autowired
    private TempService tempService;

    @ApiOperation(value="根据Id查询Temp信息", notes="MyBatis实现数据库访问demo")
    @RequestMapping(value = "/{id}",method = RequestMethod.GET)
    public Temp getTemp(@ApiParam(name="id",value="主键id",required=true) @PathVariable  Integer id)
    {
        Temp t=tempService.getTemp(id);
        return t;
    }

    @ApiOperation(value="分页查询Temp信息", notes="MyBatis实现数据库访问demo")
    @RequestMapping(value = "/paging",method = RequestMethod.GET)
    @ResponseBody
    public List<Temp> getTempPaging(@RequestParam Map<String,Object> map)
    {
        List<Temp> t=tempService.getTempPaging(map);
        return t;
    }

    @ApiOperation(value="新增Temp信息", notes="MyBatis实现数据库访问demo")
    @RequestMapping(value = "",method = RequestMethod.POST)
    public String postTemp(@RequestBody  Temp temp)
    {
        tempService.insertTemp(temp);
        return "success";
    }

    @ApiOperation(value="根据Id更新Temp信息", notes="MyBatis实现数据库访问demo")
    @RequestMapping(value = "/{id}",method = RequestMethod.PUT)
    public String putTemp(@PathVariable  Integer id,@RequestBody  Temp temp)
    {
        temp.setId(id);
        tempService.updateTemp(temp);
        return "success";
    }

    @ApiOperation(value="根据Id删除Temp信息", notes="MyBatis实现数据库访问demo")
    @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
    public String deleteTemp(@PathVariable  Integer id)
    {
        Boolean result=tempService.deleteTemp(id);
        return result.toString();
    }

}

主要实现了五个接口,简单的CRUD和一个分页。

到这里,代码基本编写完成,如无意外的话,编译后即可得到上面说的截图效果。

轻插:Swagger常用注解说明

上面代码中使用了一些Swagger基本的注解:

  • @Api:用在请求的类上,表示对类的说明
  • @ApiOperation:用在请求的方法上,说明方法的用途、作用
  • @ApiParam:用在请求的方法上,表示参数说明

主要用了这三个,@Api主要描述下整个服务组的一些说明,@ApiOperation主要描述单个服务的说明,这两个感觉还是有点必要的。

至于其他的,感觉视情况而定吧,如果要把一个服务全部描述清楚,这代码看上去真的有点恐怖。

下面是一些Swagger其他一些注解,供大家了解参考,因为没有使用到,没有深入去研究,详细的可以参考官网

  • @ApiModel: 用于类表示对类进行说明,用于参数用实体类接收
  • @ApiModelProperty:用于方法,字段
    表示对model属性的说明或者数据操作更改
  • @ApiIgnore:用于类,方法,方法参数
    表示这个方法或者类被忽略
  • @ApiImplicitParam: 用于方法
    表示单独的请求参数
  • @ApiImplicitParams:用于方法,包含多个 @ApiImplicitParam

总结

本篇主要结合Spring Boot学习笔记(四)构建RESTful API标准工程实例Spring Boot学习笔记(五)整合MyBatis实现数据库访问,填充了CURD服务的基本实现。

开发应用时,主流程实现应该没有问题了,但还有很多不足,比如日志,一些传参验证,异常捕获等。后期也会慢慢学习,分享出来。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容