仿牛客网社区论坛
项目名称:仿牛客网社区论坛
项目开发语言:JAVA
开发环境:Windows7+、Centos7
集成开发工具:IntelliJ IDEA 2019
文件传输:Xshell 5
版本控制工具:Git
数据库可视化工具:Navicat
数据库系统:MySQL 5.5、Redis 6.2
应用服务器:Apache Tomcat 8.x
构建工具:Apache Maven 3.x
项目核心技术:Spring、SpringMVC、MyBatis、SpringBoot、Redis、Kafka、Elasticsearch、Spring security、Spring Actuator
项目核心功能:SSM—-社区首页开发
SpringBoot—-社区登录模块、过滤敏感词、事务管理等.
Redis—–整合springboot,高性能存储.
Kafka——构建TB级别异步消息系统.
Elasticsearch—–开发社区搜索功能.
项目进阶—–整合spring security,构建高效安全的企业业务.
配置文件application.properties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| server.port=8080 server.servlet.context-path=/community
spring.thymeleaf.cache=false
spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/community?characterEncoding=utf-8&useSSL=false&serverTimezone=Hongkong spring.datasource.username=root spring.datasource.password=root spring.datasource.type=com.zaxxer.hikari.HikariDataSource spring.datasource.hikari.maximum-pool-size=15 spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.idle-timeout=30000
mybatis.mapper-locations=classpath:mapper/*.xml mybatis.type-aliases-package=com.tzd.community.entity mybatis.configuration.use-generated-keys=true mybatis.configuration.map-underscore-to-camel-case=true
spring.mail.host=smtp.sina.com spring.mail.port=465 spring.mail.username=tianzedeng@sina.cn spring.mail.password=a39cbaa2835b8880 spring.mail.protocol=smtps spring.mail.properties.mail.smtp.ssl.enable=true
community.path.domain=http://localhost:8080 community.path.upload=h:/project/data/upload
spring.redis.database=11 spring.redis.host=localhost spring.redis.port=6379
spring.kafka.bootstrap-servers=192.168.66.3:9092 spring.kafka.consumer.group-id=test-consumer-group spring.kafka.consumer.enable-auto-commit=true spring.kafka.consumer.auto-commit-interval=3000
spring.data.elasticsearch.cluster-name=tzd spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300
spring.main.allow-bean-definition-overriding=true
spring.task.execution.pool.core-size=5 spring.task.execution.pool.max-size=15 spring.task.execution.pool.queue-capacity=100
spring.task.scheduling.pool.size=5
spring.quartz.job-store-type=jdbc spring.quartz.scheduler-name=communityScheduler spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate spring.quartz.properties.org.quartz.jobStore.isClustered=true spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool spring.quartz.properties.org.quartz.threadPool.threadCount=5
wk.image.command=e:/wkhtmltopdf/bin/wkhtmltoimage wk.image.storage=h:/project/data/wk-images
qiniu.key.access=Y7cn8X71N5ujSHSb71ZZrQTrSzmCGbajvuAWqh5s qiniu.key.secret=4GzMiXe0L9rkgzUzaF4661PlmgWMheuLxEsBUvNX qiniu.bucket.header.name=tianzedeng qiniu.bucket.header.url=http://raiibt9ye.hb-bkt.clouddn.com qiniu.bucket.share.name=tianzhedeng qiniu.bucket.share.url=http://raijyoyfg.hb-bkt.clouddn.com
caffeine.posts.max-size=15 caffeine.posts.expire-seconds=180
|
pom.xml依赖文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.5.RELEASE</version> <relativePath/> </parent> <groupId>com.tzd.community</groupId> <artifactId>community</artifactId> <version>0.0.1-SNAPSHOT</version> <name>community</name> <description>community</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> <version>2.2.6.RELEASE</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> </dependency> <dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity5</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <dependency> <groupId>com.qiniu</groupId> <artifactId>qiniu-java-sdk</artifactId> <version>7.2.23</version> </dependency> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>2.8.0</version> </dependency>
</dependencies>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>3.1.0</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> <configuration> <skipTests> true </skipTests> </configuration> </plugin> </plugins> </build>
</project>
|
社区首页开发
首页index.html代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
| <!doctype html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="icon" href="https://static.nowcoder.com/images/logo_87_87.png"/> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossorigin="anonymous"> <link rel="stylesheet" th:href="@{/css/global.css}" /> <title>牛客网-首页</title> </head> <body> <div class="nk-container"> <header class="bg-dark sticky-top" th:fragment="header"> <div class="container"> <nav class="navbar navbar-expand-lg navbar-dark"> <a class="navbar-brand" href="#"></a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> <li class="nav-item ml-3 btn-group-vertical"> <a class="nav-link" th:href="@{/index}">首页</a> </li> <li class="nav-item ml-3 btn-group-vertical" th:if="${loginUser!=null}"> <a class="nav-link position-relative" th:href="@{/letter/list}">消息<span class="badge badge-danger" th:text="${allUnreadCount!=0?allUnreadCount:''}">12</span></a> </li> <li class="nav-item ml-3 btn-group-vertical" th:if="${loginUser==null}"> <a class="nav-link" th:href="@{/register}">注册</a> </li> <li class="nav-item ml-3 btn-group-vertical" th:if="${loginUser==null}"> <a class="nav-link" th:href="@{/login}">登录</a> </li> <li class="nav-item ml-3 btn-group-vertical dropdown" th:if="${loginUser!=null}"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <img th:src="${loginUser.headerUrl}" class="rounded-circle" style="width:30px;"/> </a> <div class="dropdown-menu" aria-labelledby="navbarDropdown"> <a class="dropdown-item text-center" th:href="@{|/user/profile/${loginUser.id}|}">个人主页</a> <a class="dropdown-item text-center" th:href="@{/user/setting}">账号设置</a> <a class="dropdown-item text-center" th:href="@{/logout}">退出登录</a> <div class="dropdown-divider"></div> <span class="dropdown-item text-center text-secondary" th:utext="${loginUser.username}">nowcoder</span> </div> </li> </ul> <form class="form-inline my-2 my-lg-0" method="get" th:action="@{/search}"> <input class="form-control mr-sm-2" type="search" aria-label="Search" name="keyword" th:value="${keyword}"/> <button class="btn btn-outline-light my-2 my-sm-0" type="submit">搜索</button> </form> </div> </nav> </div> </header>
<div class="main"> <div class="container"> <div class="position-relative"> <ul class="nav nav-tabs mb-3"> <li class="nav-item"> <a th:class="|nav-link ${orderMode==0?'active':''}|" th:href="@{/index(orderMode=0)}">最新</a> </li> <li class="nav-item"> <a th:class="|nav-link ${orderMode==1?'active':''}|" th:href="@{/index(orderMode=1)}">最热</a> </li> </ul> <button type="button" class="btn btn-primary btn-sm position-absolute rt-0" data-toggle="modal" data-target="#publishModal" th:if="${loginUser!=null}">我要发布</button> </div> <div class="modal fade" id="publishModal" tabindex="-1" role="dialog" aria-labelledby="publishModalLabel" aria-hidden="true"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="publishModalLabel">新帖发布</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <form> <div class="form-group"> <label for="recipient-name" class="col-form-label">标题:</label> <input type="text" class="form-control" id="recipient-name"> </div> <div class="form-group"> <label for="message-text" class="col-form-label">正文:</label> <textarea class="form-control" id="message-text" rows="15"></textarea> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button> <button type="button" class="btn btn-primary" id="publishBtn">发布</button> </div> </div> </div> </div> <div class="modal fade" id="hintModal" tabindex="-1" role="dialog" aria-labelledby="hintModalLabel" aria-hidden="true"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="hintModalLabel">提示</h5> </div> <div class="modal-body" id="hintBody"> 发布完毕! </div> </div> </div> </div> <ul class="list-unstyled"> <li class="media pb-3 pt-3 mb-3 border-bottom" th:each="map:${discussPosts}"> <a th:href="@{|/user/profile/${map.user.id}|}"> <img th:src="${map.user.headerUrl}" class="mr-4 rounded-circle" alt="用户头像" style="width:50px;height:50px;"> </a> <div class="media-body"> <h6 class="mt-0 mb-3"> <a th:href="@{|/discuss/detail/${map.post.id}|}" th:utext="${map.post.title}">备战春招,面试刷题跟他复习,一个月全搞定!</a> <span class="badge badge-secondary bg-primary" th:if="${map.post.type==1}">置顶</span> <span class="badge badge-secondary bg-danger" th:if="${map.post.status==1}">精华</span> </h6> <div class="text-muted font-size-12"> <u class="mr-3" th:utext="${map.user.username}">寒江雪</u> 发布于 <b th:text="${#dates.format(map.post.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-15 15:32:18</b> <ul class="d-inline float-right"> <li class="d-inline ml-2">赞 <span th:text="${map.likeCount}">11</span></li> <li class="d-inline ml-2">|</li> <li class="d-inline ml-2">回帖 <span th:text="${map.post.commentCount}">7</span></li> </ul> </div> </div> </li> </ul> <nav class="mt-5" th:if="${page.rows>0}" th:fragment="pagination"> <ul class="pagination justify-content-center"> <li class="page-item"> <a class="page-link" th:href="@{${page.path}(current=1)}">首页</a> </li> <li th:class="|page-item ${page.current==1?'disabled':''}|"> <a class="page-link" th:href="@{${page.path}(current=${page.current-1})}">上一页</a></li> <li th:class="|page-item ${i==page.current?'active':''}|" th:each="i:${#numbers.sequence(page.from,page.to)}"> <a class="page-link" th:href="@{${page.path}(current=${i})}" th:text="${i}">1</a> </li> <li th:class="|page-item ${page.current==page.total?'disabled':''}|"> <a class="page-link" th:href="@{${page.path}(current=${page.current+1})}">下一页</a> </li> <li class="page-item"> <a class="page-link" th:href="@{${page.path}(current=${page.total})}">末页</a> </li> </ul> </nav> </div> </div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" crossorigin="anonymous"></script> <script th:src="@{/js/global.js}"></script> <script th:src="@{js/index.js}"></script> </body> </html>
|
效果图如下:

开发社区登录模块
效果图如下:


前缀树算法过滤敏感词
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
| package com.tzd.community.util;
import org.apache.commons.lang3.CharUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map;
@Component public class SensitiveFilter {
private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class);
private static final String REPLACEMENT = "***";
private TrieNode rootNode = new TrieNode();
@PostConstruct public void init(){ try( InputStream inputStream = this.getClass().getClassLoader() .getResourceAsStream("sensitive-words.txt"); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); ){ String keyword; while ((keyword = bufferedReader.readLine()) != null){ this.addKeyword(keyword); } }catch (IOException e){ logger.error("加载敏感词文件失败!" + e.getMessage()); } }
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; } TrieNode tempNode = rootNode; int begin = 0; int position = 0; StringBuilder stringBuilder = new StringBuilder();
while (position < text.length()){ char c = text.charAt(position); if (isSymbol(c)){ if (tempNode == rootNode){ stringBuilder.append(c); begin++; } position++; continue; } tempNode = tempNode.getSubNode(c); if (tempNode == null){ stringBuilder.append(text.charAt(begin)); position = ++begin; tempNode = rootNode; }else if (tempNode.isKeywordEnd()){ stringBuilder.append(REPLACEMENT); begin = ++position; tempNode = rootNode; }else { position++; } } stringBuilder.append(text.substring(begin)); return stringBuilder.toString(); } private boolean isSymbol(Character c){ return !CharUtils.isAsciiAlphanumeric(c) && (c<0x2E80 || c>0x9FFF); }
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 character,TrieNode node){ subNodes.put(character,node); } public TrieNode getSubNode(Character character){ return subNodes.get(character); } }
}
|
记录日志
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| <?xml version="1.0" encoding="UTF-8"?> <configuration> <contextName>community</contextName> <property name="LOG_PATH" value="H:/project/data"/> <property name="APPDIR" value="community"/>
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}/${APPDIR}/log_error.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}/${APPDIR}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>5MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>30</maxHistory> </rollingPolicy> <append>true</append> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern> <charset>utf-8</charset> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>error</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender>
<appender name="FILE_WARN" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}/${APPDIR}/log_warn.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}/${APPDIR}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>5MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>30</maxHistory> </rollingPolicy> <append>true</append> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern> <charset>utf-8</charset> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>warn</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender>
<appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}/${APPDIR}/log_info.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_PATH}/${APPDIR}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>5MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>30</maxHistory> </rollingPolicy> <append>true</append> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern> <charset>utf-8</charset> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>info</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d %level [%thread] %logger{10} [%file:%line] %msg%n</pattern> <charset>utf-8</charset> </encoder> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>debug</level> </filter> </appender>
<logger name="com.tzd.community" level="debug"/>
<root level="info"> <appender-ref ref="FILE_ERROR"/> <appender-ref ref="FILE_WARN"/> <appender-ref ref="FILE_INFO"/> <appender-ref ref="STDOUT"/> </root>
</configuration>
|
Redis处理点赞、关注、热帖排行
效果图:



kafka处理系统通知
效果图:


Elasticsearch实现分布式搜索功能
效果图:

Spring Security实现权限控制
效果图:

