前两篇已经构建了 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 服务的基本实现
开发应用时, 主流程实现应该没有问题了, 但还有很多不足, 比如日志, 一些传参验证, 异常捕获等后期也会慢慢学习, 分享出来
来源: http://www.jianshu.com/p/3f5965f3cefd