第三章
过滤敏感词
前缀树,敏感词过滤器(定义前缀树、根据铭感词初始化前缀树、编写过滤方法)
private class TrieNode{ private boolean isKeywordEnd = false; private Map<Character,TrieNode> subNodes = new HashMap<>(); public boolean isKeywordEnd() { return isKeywordEnd; } public void setKeywordEnd(boolean keywordEnd) { isKeywordEnd = keywordEnd; } public void addSubNode(Character c, TrieNode node){ subNodes.put(c, node); } public TrieNode getSubNode(Character c){ return subNodes.get(c); } }
private void addKeyword(String keyword){ TrieNode tempNode = rootNode; for (int i = 0; i < keyword.length(); i++) { char c = keyword.charAt(i); TrieNode subNode = tempNode.getSubNode(c); if (subNode == null){ subNode = new TrieNode(); tempNode.addSubNode(c,subNode); } tempNode = subNode; if (i == keyword.length() - 1){ tempNode.setKeywordEnd(true); } } }
public String filter(String text){ if (StringUtils.isBlank(text)){ return null; } //指针1 TrieNode tempNode = rootNode; //指针2 int begin = 0; //指针3 int position = 0; //结果 StringBuilder sb = new StringBuilder(); while (begin < text.length()){ char c = text.charAt(position); if (isSymbol(c)){ if (tempNode == rootNode){ begin ++; sb.append(c); } position++; continue; } tempNode = tempNode.getSubNode(c); if (tempNode == null){ sb.append(text.charAt(begin)); position = ++begin; tempNode = rootNode; }else if (tempNode.isKeywordEnd()){ sb.append(REPLACEMENT); begin = ++position; tempNode = rootNode; }else { if (position < text.length() - 1){ position++; } } } return sb.toString(); } //判断是否为符号 private boolean isSymbol(Character c) { //0x2E80~0x9FFF是东亚文字范围 return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF); }
发布帖子
AJAX实现异步请求,网页实现增量跟新,不需要刷新页面
使用JQuery发送AJAX请求
转义标签:HtmlUtils.htmlEscape()
function publish() { $("#publishModal").modal("hide"); //获取标题和内容 var title = $("#recipient-name").val(); var content = $("#message-text").val(); //发布异步请求 $.post( CONTEXT_PATH + "/discuss/add", {"title":title,"content":content}, function (data){ data = $.parseJSON(data); //在提示框当中显示返回的消息 $("#hintBody").text(data.msg); //显示提示框 $("#hintModal").modal("show"); //2秒后自动隐藏提示框 setTimeout(function(){ $("#hintModal").modal("hide"); //刷新页面 if (data.code == 0){ window.location.reload(); } }, 2000); } ); }
帖子详情
在帖子标题上增加访问详情页面的链接
新增dao层、service层、controller层和页面
事务管理
ACID
spring提供事务管理
-
声明式-在方法上增加@Transactional(isolatiom=Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
-
REQUIRED支持当前事务,如果不存在则创建新事物
-
REQUIRED _NEW 创建一个新事物,并且暂停当前事务
可以作用于接口、接口方法、类以及类方法上。
-
-
编程式
-
注入TransactionTemplate
-
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED)
-
transactionTemplate.excute()
public void like(int userId, int entityType, int entityUserId){ redisTemplate.execute(new SessionCallback() { @Override public Object execute(RedisOperations redisOperations) throws DataAccessException { xxx redisOperations.multi(); //被事务管理的操作 return redisOperations.exec(); } }); }
-
显示评论
-
数据层
-
查询评论数据 实体类型是帖子的评论还是评论的评论
-
-
业务层
-
处理查询评论数量业务
-
-
表现层
-
显示帖子详情
-
添加评论
对添加评论做事务管理
@Transactional(isolatiom=Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
发送私信
异步的方法发送私信
$.post( CONTEXT_PATH + "/letter/send", {"toName":toName,"content":content}, function(data){ data = $.parseJSON(data); if (data.code == 0){ $("#hintBody").text("发送成功"); }else { $("#hintBody").text(data.msg); } $("#hintModal").modal("show"); setTimeout(function(){ $("#hintModal").modal("hide"); location.reload(); }, 2000); } );
统一处理异常
统一处理异常:
@ControllerAdvice用于修饰类,表示该类是Controller的全局配置类-可以进行三种配置(异常处理方案、绑定数据方案、绑定参数方案) @ControllerAdvice(annotations = Controller.class) @ExceptionHandler用于修饰方法,会在Controller出现异常后调用,用于处理捕获的异常。
@ControllerAdvice(annotations = Controller.class) public class ExceptionAdvice { private final static Logger logger = LoggerFactory.getLogger(ExceptionAdvice.class); @ExceptionHandler({Exception.class}) public void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException { logger.error("服务器异常" + e.getMessage()); for (StackTraceElement element:e.getStackTrace()){ logger.error(element.toString()); } String xRequestedWith = request.getHeader("x-requested-with"); if ("XMLHttpRequest".equals(xRequestedWith)){ response.setContentType("application/plain;charset=utf-8"); PrintWriter writer = response.getWriter(); writer.write(CommunityUtil.getJSONString(1,"服务器异常")); }else { response.sendRedirect(request.getContextPath()+"/error"); } } }
AOP 统一记录日志
发布帖子、发布评论、发送消息都需要记录日志
基于动态代理
@Component @Aspect public class ServiceLogAspect { private final static Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class); @Pointcut("execution(* com.nowcoder.community2.service.*.*(..))") public void pointcut(){ } @Before("pointcut()") public void before(JoinPoint joinPoint){ ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); String ip = request.getRemoteHost(); String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); String target = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(); logger.info(String.format("用户[%s],在[%s],访问了[%s]",ip, now, target)); } }