var editor = editormd("edit-article", {
width: "100%",
height: "100%",
// theme : "dark",
// previewTheme : "dark",
// editorTheme : "pastel-on-dark",
codeFold: true,
//syncScrolling : false,
saveHTMLToTextarea: true, // 保存 HTML 到 Textarea
searchReplace: true,
watch : true, // 关闭实时预览
htmlDecode: "style,script,iframe|on*", // 开启 HTML 标签解析,为了安
全性,默认不开启
// toolbar : false, //关闭⼯具栏
// previewCodeHighlight : false, // 关闭预览 HTML 的代码块⾼亮,默认开启
emoji: true,
taskList: true,
tocm: true, // Using [TOCM]
tex: true, // 开启科学公式TeX语⾔⽀持,默认关闭
// flowChart: true, // 开启流程图⽀持,默认关闭
// sequenceDiagram: true, // 开启时序/序列图⽀持,默认关闭,
placeholder: '开始创作...', // 占位符
path: "./dist/editor.md/lib/"
});
1. 用户点击发布新帖按钮,进入发贴页面
2. 选择版块,填入标题、正文后提交服务器
3. 服务器校验信息,并写入数据库
4. 更新用户发帖数与版块贴子数
5. 返回结果
要对帖子表、用户表、板块表同时进行操作,就需要通过事务进行管理。
参数名 | 描述 | 类型 | 默认值 | 条件 |
---|---|---|---|---|
boardId | 版块 Id | long | 必须 | |
title | 文章标题 | String | 必须 | |
content | 帖子内容 | String | 必须 |
作者 Id 需要从 Session 中获取(即当前的登录用户)。
update t_user set articleCount = articleCount + 1,updateTime = now() where id = #{id,jdbcType=BIGINT}
/**
* 贴子数增加1
* @param id
* @return
*/
void addOneArticleCountById(Long id);
/**
* 贴子数增加1
* @param id
* @return
*/
void addOneArticleCountById(Long id);
在 IArticleService 定义方法:
/**
* 发布帖⼦
* @param article 帖⼦信息
*/
// 事务管理
@Transactional
void create(Article article);
在这个方法中,需要对三个表进行更新操作,因此需要通过事务进行管理。如果在执行过程中抛出异常,那么事务将会被自动回滚。
在 IBoradService.java 中实现以下方法:
@Override
public void addOneArticleCountById(Long id) {
// 非空检验
if(id == null || id <= 0){
// 打印日志
log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
// 抛出异常
throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
}
// 查询现有的用户信息
User user = selectById(id);
// 校验用户是否存在
if (user == null) {
// 打印日志
log.info(ResultCode.FAILED_USER_NOT_EXISTS.toString());
// 抛出异常
throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
}
// 构造要更新的对象
User updateUser = new User();
updateUser.setId(user.getId()); // 用户Id
updateUser.setArticleCount(user.getArticleCount() + 1); //帖子数量+1
updateUser.setUpdateTime(new Date());// 更新时间
// 调用 DAO
int row = userMapper.updateByPrimaryKeySelective(updateUser);
if(row != 1){
// 打印日志
log.warn(ResultCode.ERROR_SERVICES.toString());
// 抛出异常
throw new ApplicationException(AppResult.failed(ResultCode.ERROR_SERVICES));
}
}
在 BoardServiceImpl.java 中实现以下方法:
@Override
public void addOneArticleCountById(Long id) {
// 非空检验
if(id == null || id <= 0){
// 打印日志
log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
// 抛出异常
throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
}
// 查询板块信息
Board board = selectById(id);
// 检验版块是否存在
if(board == null){
// 打印日志
log.warn(ResultCode.FAILED_BOARD_NOT_EXISTS.toString());
// 抛出异常
throw new ApplicationException(AppResult.failed(ResultCode.FAILED_BOARD_NOT_EXISTS));
}
// 构造要更新的对象
Board updateBoard = new Board();
updateBoard.setId(board.getId()); // 版块Id
updateBoard.setArticleCount(board.getArticleCount() + 1); //帖子数量
updateBoard.setUpdateTime(new Date());// 更新时间
// 调用 DAO
int row = boardMapper.updateByPrimaryKeySelective(updateBoard);
}
在以上的实现方法写好后,编写测试代码:
在 UserServiceImplTest.java 文件中:
@Test
@Transactional
void addOneArticleCountById() {
userService.addOneArticleCountById(1l);
System.out.println("更新成功");
userService.addOneArticleCountById(2l);
System.out.println("更新成功");
}
在 BoardServiceImplTest.java 中:
@Test
void addOneArticleCountById() {
boradService.addOneArticleCountById(1l);
System.out.println("更新成功");
boradService.addOneArticleCountById(2l);
System.out.println("更新成功");
boradService.addOneArticleCountById(55l);
System.out.println("更新成功");
}
加了事务的注解后,测试的结果不在持久化到数据库,当测试通过后,写入的数据会被回滚。
@Test
void create() {
Article article = new Article();
article.setBoardId(1l);
article.setUserId(1l);
article.setTitle("单元测试标题");
article.setContent("单元测试内容");
// 调用service
articleService.create(article);
System.out.println("写入成功");
}
@ApiOperation("发布帖子")
@PostMapping("/create")
public AppResult create(HttpServletRequest request,
@ApiParam("版块Id") @RequestParam("boardId") @NonNull Long boardId,
@ApiParam("帖子标题") @RequestParam("title") @NonNull String title,
@ApiParam("帖子正文") @RequestParam("content") @NonNull String content){
// 获取用户信息
HttpSession session = request.getSession(false);
User user =(User)session.getAttribute(AppConfig.SESSION_USER_KEY);
// 校验用户状态
if(user.getState() == 1){
// 用户已禁言,返回提示
return AppResult.failed(ResultCode.FAILED_USER_BANNED);
}
// 构造帖子对象
Article article = new Article();
article.setUserId(user.getId()); // 当前登录用户就是作者
article.setBoardId(boardId); // 版块Id
article.setTitle(title); // 帖子标题
article.setContent(content); // 帖子正文
// 调用 Service
articleService.create(article);
// 返回结果
return AppResult.success("贴子发布成功");
}
// 构造帖子对象
let postData = {
boardId : boardIdEl.val(),
title : titleEl.val(),
content : contentEl.val()
};
// 提交, 成功后调用changeNavActive($('#nav_board_index'));回到首页并加载帖子列表
// contentType: 'application/x-www-form-urlencoded'
$.ajax({
type : 'post',
url : 'article/create',
contentType : 'application/x-www-form-urlencoded',
data : postData,
// 成功回调
success: function(respData){
if(respData.code == 0){
// 成功后跳转到首页
changeNavActive($('#nav_board_index'));
}else{
// 失败
$.toast({
heading : '警告',
text : respData.message,
icon : 'Warning'
});
}
},
// 失败回调
error: function(){
$.toast({
heading : '错误',
text : '出错了,请联系管理员',
icon : 'error'
});
}
1. 用户点击帖子,将帖子 Id 做为参数向服务器发送请求2. 服务器查询帖子信息3. 帖子访问次数加14. 返回查询结果
那么此时的操作有一个查询,一个更新需要用事务进行管理吗?
答:只对一条记录进行更新时,不需要事务。
在帖子详情中,必须包含帖子的全部信息。
/**
* 根据帖子Id 查询帖子详情
* @param id
* @return
*/
Article selectById(@Param("id") Long id);
/**
* 根据帖子Id 查询帖子详情
* @param id
* @return
*/
Article selectById(Long id);
@Override
public Article selectById(Long id) {
// 非空检验
if(id == null || id <= 0){
// 打印日志
log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
// 抛出异常
throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
}
// 调用 DAO
Article article = articleMapper.selectById(id);
// 返回结果
return article;
}
@Test
void selectById() throws JsonProcessingException {
Article article = articleService.selectById(1l);
System.out.println(objectMapper.writeValueAsString(article));
article = articleService.selectById(8l);
System.out.println(objectMapper.writeValueAsString(article));
article = articleService.selectById(100l);
System.out.println(objectMapper.writeValueAsString(article));
}
测试结果:
@ApiOperation("根据Id查询帖⼦详情")
@GetMapping("/getById")
public AppResult getDetails(@ApiParam("帖⼦Id")
@RequestParam("id")
@NonNull Long id) {
// 调⽤Service层获取帖⼦详情
Article article = articleService.selectById(id);
// 校验
if (article == null) {
return AppResult.failed("帖子不存在");
}
// 返回成功信息
return AppResult.success(article);
}
$.ajax({
type : 'get',
url : '/article/getById?id=' + currentArticle.id,
// 成功回调
success: function(respData){
if(respData.code == 0){
// 把查询到的数据设置到页面上
initArticleDetails(respData.data);
}else{
// 失败
$.toast({
heading : '警告',
text : respData.message,
icon : 'Warning'
});
}
},
// 失败回调
error: function(){
$.toast({
heading : '错误',
text : '出错了,请联系管理员',
icon : 'error'
});
}
});