之前已经完成了添加文章和查询的接口,接下来继续实现以下接口
- 查询所有
- 更新
- 删除
Controller 层
在 postApi.java里面添加
@GetMapping("")
public List<Post> all() {
return postService.all();
}
/**
* 更新文章,需要登录
* @param post 需要修改的内容
* @param id 文章 id
* @param currentUser 当前用户
* @return 更新之后的文章
*/
@LoginRequired
@PutMapping("/{id}")
public Post update(@RequestBody Post post, @PathVariable int id, @CurrentUser User currentUser) {
post.setId(id);
return postService.update(post, currentUser);
}
/**
* 删除文章,需要登录
* @param id 文章 id
* @param currentUser 当前登录用户
* @return 提示信息
*/
@LoginRequired
@DeleteMapping("/{id}")
public Object delete(@PathVariable int id, @CurrentUser User currentUser) {
postService.delete(id, currentUser);
JSONObject jsonObject = new JSONObject();
jsonObject.put("message", "删除成功");
return jsonObject;
}
在这段代码里面,使用了 @LoginRequired
注解保护更新和删除接口(使用自定义注解实现登录拦截)。同样使用了 @CurrentUser
注解来注入当前登录用户(通过自定义注解获取当前用户)。
delete
方法请求成功之后返回 { "message": "删除成功" }
,和之前写的请求错误时返回的格式一样。为了避免将来使用我们接口的人感到迷惑,将接口请求错误时的响应修改为 { "error": "error message" }
的形式:将 GlobalExceptionHandler.java 、AuthenticationApi.java、PostApi.java、UserApi.java 这几个文件里面 jsonObject.put("message", "......");
修改为 jsonObject.put("error", "......");
Service 层
在 postService.java 里面添加
public List<Post> all() {
return postMapper.all();
}
public Post update(Post post, User currentUser) {
checkNotNull(post.getId(), "id不能为空");
checkOwner(post.getId(), currentUser);
postMapper.update(post);
return findById(post.getId());
}
private void checkOwner(Integer id, User currentUser) {
Post post = findById(id);
if (!post.getAuthorId().equals(currentUser.getId())) {
throw new RuntimeException("不能删除或修改别人的文章");
}
}
public void delete(int id, User currentUser) {
checkOwner(id, currentUser);
postMapper.delete(id);
}
只有作者才可以更新自己的文章,所以添加一个 checkOwner
的私有方法。
update
方法里面使用了 Google Guava 的 checkNotNull
方法,当前也可以自己写 if
语句判空,但 Guava 提供很多功能,能帮助我们编写出更优雅的代码。
在 pom.xml 中添加 guava 的依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
</dependency>
更多Guava 相关的的知识可以看看使用Guava编写优雅代码
checkNotNull
是 Guava Preconditions
类里面的一个静态方法,需要静态导入
import static com.google.common.base.Preconditions.checkNotNull;
mapper
首先将 postMapper
的 findOne
拆成下面这种形式,select-post
那段 SQL 就可以在 all
方法中复用了
<select id="findOne" resultMap="PostResultMap">
<include refid="select-post" />
<where>
<if test="id!=null">
AND post.id=#{id}
</if>
</where>
</select>
<select id="all" resultMap="PostResultMap">
<include refid="select-post" />
</select>
<sql id="select-post" >
SELECT
post.id,
post.author_id ,
post.title ,
post.content ,
post.create_time ,
post.update_time,
<!-- 作者信息,password 不需要就不查了 -->
`user`.id as author__id,
`user`.`name` as author__name
FROM post
LEFT JOIN `user` ON `user`.id=post.author_id
</sql>
<select id="all" resultMap="PostResultMap">
<include refid="select-post" />
</select>
<update id="update">
UPDATE post
<set>
<if test="title!=null">
title=#{title},
</if>
<if test="content!=null">
content=#{content},
</if>
</set>
where post.id=#{id}
</update>
<delete id="delete">
DELETE FROM post WHERE post.id=#{id}
</delete>
测试
启动项目,使用 postman 测试一下三个接口
GET api/post
UPDATE api/post/{id}
DELETE api/post/{id}
查看项目完整代码
项目地址: https://github.com/hyrijk/spring-boot-blog
克隆项目到本地
git clone https://github.com/hyrijk/spring-boot-blog.git
checkout 到当前版本
git checkout 3594fc7eb5dddeec52ad5bddeedc06678178b5bd
完。