Java课程项目——教育论坛系统成员博客
注意本文仅是课程项目的展示,不是教程性文章!!!
一个小小的链接: 本文对应的团队博客地址
负责部分:
问题详情页面展示的内容及其实现
(问题的标题和描述读取,文章的修改功能,删除,置顶,回复功能等)
以及搜索功能的实现
功能实现的逻辑
从前端拆解开说明实现的方法
问题详情页
搜索:
标题问题的展示
从首页或者其它页面进入问题详情页面时,网址上会携带问题的ID,通过Controller的GetMapping抓取id,通过id从数据库查询,然后在前端展示即可完成,具体逻辑在代码注释区域:
@GetMapping("/question/{id}")
public String question(@PathVariable(name = "id") String id,
Model model){
QuestionDTO questionDTO = questionService.getById(Integer.parseInt(id));
//通过Service层的方法从数据库找到这个问题
//查看回复数量↓
questionDTO.setCommentCount(commentService.countByParentId(Integer.parseInt(id)));
model.addAttribute("questionId",id);
model.addAttribute("question",questionDTO);
//model 实现网页读取数据
//按照ID寻找问题↑
questionService.incView(id);
//浏览数的增加方法
List<CommentDTO> commentDTOList = commentService.getByParentIdList(Integer.parseInt(id));
model.addAttribute("comments",commentDTOList);
//回复列表的实现
return "question";
}
Service层查找问题的方法
public QuestionDTO getById(Integer id) {
Question question = questionMapper.selectByPrimaryKey(id);
QuestionDTO questionDTO = new QuestionDTO();
BeanUtils.copyProperties(question,questionDTO);
User user = userMapper.selectByPrimaryKey(question.getCreator());
questionDTO.setUser(user);
return questionDTO;
}
通过QusetionDTO层,我们就可以在前端界面查看具体的数据了
@Data
public class QuestionDTO {
private Integer id;
private String title;
private String description;
private String tag;
private Long gmtCreate;
private Long gmtModified;
private Integer creator;
private Integer viewCount;
private Integer commentCount;
private Integer likeCount;
private Boolean isTop;
private User user;
}
这样通过model在前端就可以读取到标题,描述,创建时间,发起人,浏览量,点赞量和置顶情况了。
修改,删除,置顶功能的实现
首先进行用户的判断,帖子的发起者可以点赞,修改,和删除,没有置顶权限
管理员拥有点赞,删除和置顶
登陆的浏览者只能点赞
没有登陆的人无法点赞
判断的逻辑很简单,只需要用thymeleaf中的th:if就可以实现
然后就是这几个按钮实现的逻辑,它们基本相同,仅仅是对数据库的操作不同:
修改携带问题的ID传到Pulish页在进行一次编辑就可以编辑
删除携带问题ID传到Delete页进行删除
置顶携带问题ID到top界面进行判断和置顶
以置顶为例:
<li><a th:href="@{'/settop/'+${id}}" th:if="${ not question.isTop}">确认置顶帖子</a></li>
<li><a th:href="@{'/settop/'+${id}}" th:if="${question.isTop}">取消置顶帖子</a></li>
携带ID进行跳转,TopController中的GetMapping会抓取到QuestionId,进行置顶和取消置顶的操作
@GetMapping("/settop/{id}")
public String setTop(@PathVariable(name = "id") String id,
Model model){
Question question = questionMapper.selectByPrimaryKey(Integer.parseInt(id));
if(question.getIsTop() == true){
question.setIsTop(false);
}else{
question.setIsTop(true);
}
QuestionExample questionExample = new QuestionExample();
questionExample.createCriteria()
.andIdEqualTo(Integer.parseInt(id));
questionMapper.updateByExampleSelective(question,questionExample);
return "redirect:/";
}
回复列表的查询
在Controller中进行的操作可以读取当前问题的回复量:
List<CommentDTO> commentDTOList = commentService.getByParentIdList(Integer.parseInt(id));
model.addAttribute("comments",commentDTOList);
在CommentService对应的搜索逻辑
public List<CommentDTO> getByParentIdList(Integer id) {
//CommentDTO commentDTOs = new CommentDTO();
CommentExample commentExample =new CommentExample();
commentExample.createCriteria()
.andParentIdEqualTo(id);
List<Comment> comments = commentMapper.selectByExample(commentExample);
List<CommentDTO> commentDTOList = new ArrayList<>();
for(Comment comment:comments){
User user = userMapper.selectByPrimaryKey(comment.getCommentator());
CommentDTO commentDTO = new CommentDTO();
BeanUtils.copyProperties(comment,commentDTO);
commentDTO.setUser(user);
commentDTOList.add(commentDTO);
}
//System.out.println(commentDTOList.get(0).getLikeCount());
return commentDTOList;
th:each遍历读取
<div class="media" th:each=" comment : ${comments}">
<div class="media-left">
<a th:href="@{'/profile/'+${comment.user.id}}">
<img class="media-object img-rounded"
th:src="${comment.user.avatarUrl}">
</a>
</div>
<div class="media-body">
<h5 class="media-heading">
<a th:text="${comment.user.name}" th:href="@{'/profile/'+${comment.user.id}}"></a>
</h5>
<span th:text="${comment.content}"></span><br>
<div class="btn-group btn-group-sm" role="group" aria-label="...">
<a th:href="@{'/like/'+${comment.id}+'/2'}">
<button type="button" class="btn btn-info glyphicon glyphicon-thumbs-up"
th:text="${comment.likeCount}"></button>
</a>
</div>
<span class="text-desc" th:text="' | 回复时间:'+${#dates.format(comment.gmtCreate,'yyyy-MM-dd HH:mm')}"></span>
</div>
<hr class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
</div>
回复功能的体现
使用了POST方法
<form th:action="@{'/question/'+${questionId}}" method="post">
<div class="form-group">
<label for="comment">请输入你要回复的内容</label>
<div class="form-group">
<textarea name="comment" id="comment" th:text="${comment}" class="form-control" cols="10"
rows="8"></textarea>
</div>
</div>
<div class="container-fluid main">
<div class="row">
<div class="col-lg-9 col-md-12 col-sm-12 col-xs-12">
<div class="alert alert-danger col-lg-12 col-md-12 col-sm-12 col-xs-12"
th:text="${error}" th:if="${error != null}"></div>
</div> <!-- 展示错误信息 -->
<div class="col-lg-3 col-md-12 col-sm-12 col-xs-12"><button type="submit" class="btn btn-success btn-publish">
回复帖子
</button>
</div>
</div></div>
</form>
PostMapping方法拿到,写入数据库
@PostMapping ("/question/{id}")
public String doComment(@PathVariable(name = "id") String id,
@RequestParam("comment") String comment,
Model model,
HttpServletRequest request){
if (comment == null || comment == "") {
model.addAttribute("error", "回复的内容不能为空");
return "question";
}
User user = (User) request.getSession().getAttribute("user");
if (user == null) {
model.addAttribute("error", "用户未登陆");
return "question";
}
Comment newComment = new Comment();
newComment.setContent(comment);
newComment.setCommentator(user.getId());
newComment.setParentId(Integer.parseInt(id));
newComment.setLikeCount(0);
commentService.createOrUpdate(newComment);
QuestionDTO questionDTO = questionService.getById(Integer.parseInt(id));
//查看回复数量↓
questionDTO.setCommentCount(commentService.countByParentId(Integer.parseInt(id)));
model.addAttribute("questionId",id);
model.addAttribute("question",questionDTO);
//按照ID寻找问题↑
List<CommentDTO> commentDTOList = commentService.getByParentIdList(Integer.parseInt(id));
model.addAttribute("comments",commentDTOList);
if(user.getQuestionCount()==null) {
user.setQuestionCount(0);
}
if(user.getCommentCount()==null) {
user.setCommentCount(0);
}
if(user.getActive()==null) {
user.setActive(0);
}
user.setCommentCount(user.getCommentCount()+1);
user.setActive(user.getActive()+3);
userMapper.updateByPrimaryKey(user);
return "question";
}
public void createOrUpdate(Comment newComment) {
newComment.setGmtCreate(System.currentTimeMillis());
newComment.setGmtModified(System.currentTimeMillis());
commentMapper.insertSelective(newComment);
}
搜索功能的实现
前端使用get语句
<form class="navbar-form navbar-left" action="/" method="get">
<div class="form-group">
<input type="text" class="form-control" name="search" placeholder="寻找你想要的帖子">
</div>
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-search" aria-hidden="true"/>查找</button>
</form>
后端使用数据库的模糊搜索
if(!StringUtils.isNullOrEmpty(search)){
PagingDTO pagination= questionService.list(page,size,search);
model.addAttribute("pagination",pagination);
return "index";
}
QuestionExample searchExample = new QuestionExample();
searchExample.createCriteria()
.andTitleLike("%"+search+"%");
Integer totalCount=(int)questionMapper.countByExample(searchExample);
一些小细节的完善
回复数的统计
public Integer countByParentId(int parentId) {
//因为countByExample 返回的是LONG类型,但是在定义数据库的时候将count定义未Integer类型,所以临时在这里进行一下强制类型转换
Long commentCountLong;
Integer commentCountInt;
CommentExample commentExample = new CommentExample();
commentExample.createCriteria()
.andParentIdEqualTo(parentId);
commentCountLong = commentMapper.countByExample(commentExample);
commentCountInt = commentCountLong.intValue();
Integer commentCount = commentCountInt;
return commentCount;
}
浏览数的实现
在Controller里实现一个增加一个方法,每次浏览一次就实现浏览数加一就可以实现了
总结和反思
这个项目其实并不完善,通过完成这个项目使我明白了完成一个项目需要比较大的工作量,而且大家可以看到我写的这一部分代码其实非常的简陋,许多逻辑也还存在着大量的漏洞,没有考虑的地方有很多,或许现在的它并不具备完善的功能,但是我们小组依然想在课程设计完成之后继续完善这个项目,使它逐渐完善起来。