置顶、加精、删除
1.导包thymeleaf和springsecurity5的整合
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
功能实现
-
点击“置顶”、“加精”、“删除”,修改帖子的状态
在DiscussPostMapper增加修改方法
//置顶帖子 加精帖子的方法 int updateType(int id, int type); int updateStatus(int id, int status);
DiscussPostService、DiscussPostController相应增加方法,注意在Es中同步变化
<update id="updateType"> update discuss_post set type = #{type} where id = #{id} </update> <update id="updateStatus"> update discuss_post set status = #{status} where id = #{id} </update> ------------------------ //置顶 public int updateType(int id, int type){ return discussPostMapper.updateType(id, type); } public int updateStatus(int id, int status){ return discussPostMapper.updateType(id, status); } -------------------------- //置顶 /** * * @param id 帖子id * @return */ @RequestMapping(path = "/top",method = RequestMethod.POST) @ResponseBody public String setTop(int id){ discussPostService.updateType(id,1); //将帖子数据同步到es Event event = new Event() .setTopic(TOPIC_PUBLISH) .setEntityType(ENTITY_TYPE_POST) .setEntityId(id) .setUserId(hostHolder.getUser().getId()); eventProducer.fireEvent(event); return CommunityUtil.getJSONString(0); } //加精 @RequestMapping(path = "/wonderful",method = RequestMethod.POST) @ResponseBody public String setWonderful(int id){ discussPostService.updateStatus(id,1); //将帖子数据同步到es Event event = new Event() .setTopic(TOPIC_PUBLISH) .setEntityType(ENTITY_TYPE_POST) .setEntityId(id) .setUserId(hostHolder.getUser().getId()); eventProducer.fireEvent(event); return CommunityUtil.getJSONString(0); } //删除 @RequestMapping(path = "/delete",method = RequestMethod.POST) @ResponseBody public String setDelete(int id){ discussPostService.updateStatus(id,2); //从es删除帖子 Event event = new Event() .setTopic(TOPIC_DELETE) .setEntityType(ENTITY_TYPE_POST) .setEntityId(id) .setUserId(hostHolder.getUser().getId()); eventProducer.fireEvent(event); return CommunityUtil.getJSONString(0); }
- 要在EventConsumer增加消费删帖事件
//消费者发帖的方法 //监听主题为TOPIC_PUBLISH的事件 @KafkaListener(topics = {TOPIC_PUBLISH}) public void handlePublishMessage(ConsumerRecord record){ //判断是否为空 if (record == null || record.value() == null){ logger.error("消息的内容为空"); return; } //获取生产者的event,通过获得的json字符串转换为Event对象 Event event = JSONObject.parseObject(record.value().toString(), Event.class); if (event == null){ logger.error("消息格式错误"); return; } //查询帖子信息 DiscussPost discussPost = discussPostService.findDiscussPostById(event.getEntityId()); //存入es elasticsearchService.saveDiscussPost(discussPost); } //删除帖子 @KafkaListener(topics = {TOPIC_DELETE}) public void handleDeleteMessage(ConsumerRecord record){ //判断是否为空 if (record == null || record.value() == null){ logger.error("消息的内容为空"); return; } //获取生产者的event,通过获得的json字符串转换为Event对象 Event event = JSONObject.parseObject(record.value().toString(), Event.class); if (event == null){ logger.error("消息格式错误"); return; } //删除es elasticsearchService.deleteDiscussPost(event.getEntityId()); }
修改html和js文件
discusspost-detail.html
<!-- 添加 thymeleaf和spring-security整合的信息--> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security"> <!-- 标题 --> <div class="float-right"> <input type="hidden" id="postId" th:value="${post.id}"> <button type="button" class="btn btn-danger btn-sm" id="topBtn" th:disabled="${post.type==1}" sec:authorize="hasAnyAuthority('moderator')">置顶 </button> <button type="button" class="btn btn-danger btn-sm" id="wonderfulBtn" th:disabled="${post.status==1}" sec:authorize="hasAnyAuthority('moderator')">加精 </button> <button type="button" class="btn btn-danger btn-sm" id="deleteBtn" th:disabled="${post.status==2}" sec:authorize="hasAnyAuthority('admin')">删除 </button> </div>
discuss.js
/*在加载静态页面后调用以下3个方法:置顶 加精 删除*/ $(function () { $("#topBtn").click(setTop); $("#wonderfulBtn").click(setWonderful); $("#deleteBtn").click(setDelete); }); //点赞 function like(btn, entityType, entityId, entityUserId, postId) { $.post( CONTEXT_PATH + "/like", {"entityType":entityType,"entityId":entityId,"entityUserId":entityUserId,"postId":postId}, function(data) { data = $.parseJSON(data); if(data.code == 0) { $(btn).children("i").text(data.likeCount); $(btn).children("b").text(data.likeStatus==1?'已赞':"赞"); } else { alert(data.msg); } } ); } //置顶 function setTop() { $.post( CONTEXT_PATH + "/discuss/top", {"id":$("#postId").val()}, function (data) { data = $.parseJSON(data); if (data.code==0){ $("#topBtn").attr("disabled","disabled"); }else { alert(data.msg); } } ); } //加精 function setWonderful() { $.post( CONTEXT_PATH + "/discuss/wonderful", {"id":$("#postId").val()}, function (data) { data = $.parseJSON(data); if (data.code==0){ $("#wonderfulBtn").attr("disabled","disabled"); }else { alert(data.msg); } } ); } //删除 function setDelete() { $.post( CONTEXT_PATH + "/discuss/delete", {"id":$("#postId").val()}, function (data) { data = $.parseJSON(data); if (data.code==0){ location.href = CONTEXT_PATH + "/index"; }else { alert(data.msg); } } ); }
权限管理
- 版主可以执行“置顶”、“加精”操作。管理员可以执行“删除”操作。
- 在SecurityConfig类下配置,置顶、加精、删除的访问权限。
按钮显示
- 版主可以看到“置顶”、“加精”按钮。管理员可以看到“删除“按钮。
- 导包:thymeleaf-extras-springsecurity5,thymeleaf对security的支持。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
//Security的配置类
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter implements CommunityConstant {
//忽略静态资源,不对静态资源进行拦截
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 对于以下列出的所有路径
.antMatchers(
"/user/setting",// 用户设置
"/user/upload",// 用户文件上传
"/discuss/add",// 帖子发布
"/comment/add/**",// 评论发布
"/letter/**",// 私信相关内容
"/notice/**",// 通知相关内容
"/like",// 点赞
"/follow",// 加关注
"/unfollow"// 取消关注
)
// 只要有以下相关权限,都可以访问
.hasAnyAuthority(
AUTHORITY_USER,// 权限: 普通用户
AUTHORITY_ADMIN,// 权限: 管理员
AUTHORITY_MODERATOR// 权限: 版主
)
// 对于以下列出的所有路径
.antMatchers(
"/discuss/top",
"/discuss/wonderful"
)
// 只有具有以下列出的权限才可以访问
.hasAnyAuthority(
AUTHORITY_MODERATOR// 权限: 版主
)
// 对于以下列出的所有路径
.antMatchers(
"/discuss/delete",
"/data/**"
)
// 只有具有以下列出的权限才可以访问
.hasAnyAuthority(
AUTHORITY_ADMIN
)
// 除了以上列出的权限限制约定外,其他请求路径都放行
.anyRequest().permitAll()
//
.and().csrf().disable();
//权限不够时
// 如果权限不够时的处理
http.exceptionHandling()
// 没有登录时的处理
.authenticationEntryPoint(new AuthenticationEntryPoint() {
// 没有登录时的处理方法
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException e)
throws IOException, ServletException {
// 如果请求x-requested-with 中头包含XMLHttpRequest 说明是异步请求
String xRequestedWith = request.getHeader("x-requested-with");
if ("XMLHttpRequest".equals(xRequestedWith)) {
// 设置响应体是json 格式(因为是异步请求,所以返回内容要是json格式)
response.setContentType("application/plain;charset=utf-8");
// 拿到输出流,输出返回内容给前端页面
PrintWriter writer = response.getWriter();
writer.write(CommunityUtil.getJSONString(403, "你还没有登录哦!"));
} else {// 不是异步请求
// 重定向到登录页面
response.sendRedirect(request.getContextPath() + "/login");
}
}
})
// 拒绝访问(权限不足时的处理)
.accessDeniedHandler(new AccessDeniedHandler() {
// 权限不足
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException e)
throws IOException, ServletException {
String xRequestedWith = request.getHeader("x-requested-with");
if ("XMLHttpRequest".equals(xRequestedWith)) {
// 设置响应体是json 格式(因为是异步请求,所以返回内容要是json格式)
response.setContentType("application/plain;charset=utf-8");
// 拿到输出流,输出返回内容给前端页面
PrintWriter writer = response.getWriter();
writer.write(CommunityUtil.getJSONString(403, "你没有访问此功能的权限!"));
} else {// 不是异步请求
// 重定向到没有权限页面
response.sendRedirect(request.getContextPath() + "/denied");
}
}
});
// Security底层默认会拦截/logout请求,进行退出处理.
// 覆盖它默认的逻辑,才能执行我们自己的退出代码.
http.logout().logoutUrl("/securitylogout");
}
}