├── src
├── main
│ ├── resources
│ │ ├── sensitive-words.txt
│ │ ├── static
│ │ │ ├── css
│ │ │ │ ├── login.css
│ │ │ │ ├── letter.css
│ │ │ │ ├── discuss-detail.css
│ │ │ │ └── global.css
│ │ │ ├── img
│ │ │ │ ├── 404.png
│ │ │ │ ├── error.png
│ │ │ │ └── captcha.png
│ │ │ ├── js
│ │ │ │ ├── register.js
│ │ │ │ ├── discuss.js
│ │ │ │ ├── index.js
│ │ │ │ ├── letter.js
│ │ │ │ ├── profile.js
│ │ │ │ └── global.js
│ │ │ └── html
│ │ │ │ ├── student.html
│ │ │ │ └── ajax-demo.html
│ │ ├── application.properties
│ │ ├── templates
│ │ │ ├── demo
│ │ │ │ └── view.html
│ │ │ ├── mail
│ │ │ │ ├── demo.html
│ │ │ │ ├── forget.html
│ │ │ │ └── activation.html
│ │ │ ├── site
│ │ │ │ ├── operate-result.html
│ │ │ │ ├── admin
│ │ │ │ │ └── data.html
│ │ │ │ ├── forget.html
│ │ │ │ ├── profile.html
│ │ │ │ ├── register.html
│ │ │ │ ├── followee.html
│ │ │ │ └── follower.html
│ │ │ └── error
│ │ │ │ ├── 404.html
│ │ │ │ └── 500.html
│ │ ├── mapper
│ │ │ ├── comment-mapper.xml
│ │ │ ├── discusspost-mapper.xml
│ │ │ ├── user-mapper.xml
│ │ │ └── message-mapper.xml
│ │ └── logback-spring.xml
│ └── java
│ │ └── com
│ │ └── nowcoder
│ │ └── community
│ │ ├── dao
│ │ ├── AlphaDao.java
│ │ ├── AlphaDaoHibernateImpl.java
│ │ ├── AlphaDaoMyBatisImpl.java
│ │ ├── CommentMapper.java
│ │ ├── UserMapper.java
│ │ ├── DiscussPostMapper.java
│ │ ├── LoginTicketMapper.java
│ │ └── MessageMapper.java
│ │ ├── entity
│ │ ├── LoginTicket.java
│ │ ├── Message.java
│ │ ├── Comment.java
│ │ ├── Page.java
│ │ ├── DiscussPost.java
│ │ └── User.java
│ │ ├── CommunityApplication.java
│ │ ├── annotation
│ │ └── LoginRequired.java
│ │ ├── config
│ │ ├── AlphaConfig.java
│ │ ├── WebMvcConfig.java
│ │ ├── RedisConfig.java
│ │ ├── KaptchaConfig.java
│ │ └── interceptor
│ │ │ ├── LoginRequiredInterceptor.java
│ │ │ └── LoginTicketInterceptor.java
│ │ ├── utils
│ │ ├── HostHolder.java
│ │ ├── CookieUtil.java
│ │ ├── CommunityConstant.java
│ │ ├── MailClient.java
│ │ ├── CommunityUtil.java
│ │ ├── RedisKeyUtil.java
│ │ └── SensitiveFilter.java
│ │ ├── service
│ │ ├── CommentService.java
│ │ ├── AlphaService.java
│ │ ├── DiscussPostService.java
│ │ ├── MessageService.java
│ │ ├── LikeService.java
│ │ ├── FollowService.java
│ │ └── UserService.java
│ │ ├── aspect
│ │ ├── AlphaAspect.java
│ │ └── ServiceLogAspect.java
│ │ └── controller
│ │ ├── advice
│ │ └── ExceptionAdvice.java
│ │ ├── LikeController.java
│ │ ├── HomeController.java
│ │ ├── FollowController.java
│ │ ├── AlphaController.java
│ │ ├── MessageController.java
│ │ ├── DiscussPostController.java
│ │ ├── UserController.java
│ │ └── LoginController.java
└── test
│ └── java
│ └── com
│ └── nowcoder
│ └── community
│ ├── SensitiveTest.java
│ ├── LoggerTests.java
│ ├── MailTest.java
│ ├── CommunityApplicationTests.java
│ └── MapperTests.java
├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ ├── maven-wrapper.properties
│ └── MavenWrapperDownloader.java
├── .gitignore
├── pom.xml
├── mvnw.cmd
└── README.md
/src/main/resources/sensitive-words.txt:
--------------------------------------------------------------------------------
1 | 赌博
2 | 吸毒
3 | 嫖娼
4 | 斗殴
5 |
--------------------------------------------------------------------------------
/src/main/resources/static/css/login.css:
--------------------------------------------------------------------------------
1 | .main .container {
2 | width: 720px;
3 | }
4 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pallscall/NowcoderForum/HEAD/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/src/main/resources/static/img/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pallscall/NowcoderForum/HEAD/src/main/resources/static/img/404.png
--------------------------------------------------------------------------------
/src/main/resources/static/img/error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pallscall/NowcoderForum/HEAD/src/main/resources/static/img/error.png
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pallscall/NowcoderForum/HEAD/src/main/resources/application.properties
--------------------------------------------------------------------------------
/src/main/resources/static/img/captcha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pallscall/NowcoderForum/HEAD/src/main/resources/static/img/captcha.png
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip
2 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/dao/AlphaDao.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.dao;
2 |
3 | public interface AlphaDao {
4 |
5 | String select();
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/resources/static/css/letter.css:
--------------------------------------------------------------------------------
1 | .main .nav .badge {
2 | position: absolute;
3 | top: -3px;
4 | left: 68px;
5 | }
6 |
7 | .main .media .badge {
8 | position: absolute;
9 | top: 12px;
10 | left: -3px;
11 | }
12 |
13 | .toast {
14 | max-width: 100%;
15 | width: 80%;
16 | }
--------------------------------------------------------------------------------
/src/main/resources/templates/demo/view.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Teacher
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/main/resources/templates/mail/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 | 欢迎你,
9 |
10 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/dao/AlphaDaoHibernateImpl.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.dao;
2 |
3 | import org.springframework.stereotype.Repository;
4 |
5 | @Repository("alphaHibernate")
6 | public class AlphaDaoHibernateImpl implements AlphaDao {
7 | @Override
8 | public String select() {
9 | return "Hibernate";
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/resources/static/css/discuss-detail.css:
--------------------------------------------------------------------------------
1 | .content {
2 | font-size: 16px;
3 | line-height: 2em;
4 | }
5 |
6 | .replyform textarea {
7 | width: 100%;
8 | height: 200px;
9 | }
10 |
11 | .floor {
12 | background: #dcdadc;
13 | padding: 4px 12px;
14 | border-radius: 3px;
15 | font-size: 14px;
16 | }
17 |
18 | .input-size {
19 | width: 100%;
20 | height: 35px;
21 | }
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/entity/LoginTicket.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.entity;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.Date;
6 |
7 | /**
8 | * 登录凭证实体类
9 | */
10 | @Data
11 | public class LoginTicket {
12 | private int id;
13 | private int userId;
14 | private String ticket;
15 | private int status;
16 | private Date expired;
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/dao/AlphaDaoMyBatisImpl.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.dao;
2 |
3 | import org.springframework.context.annotation.Primary;
4 | import org.springframework.stereotype.Repository;
5 |
6 | @Repository
7 | @Primary
8 | public class AlphaDaoMyBatisImpl implements AlphaDao{
9 | @Override
10 | public String select() {
11 | return "MyBatis";
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/CommunityApplication.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class CommunityApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(CommunityApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/entity/Message.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.entity;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.Date;
6 |
7 | /**
8 | * 私信
9 | */
10 | @Data
11 | public class Message {
12 | private int id;
13 | private int fromId;
14 | private int toId;
15 | private String conversationId;
16 | private String content;
17 | private int status;
18 | private Date createTime;
19 | }
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | /target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 | .sts4-cache
13 |
14 | ### IntelliJ IDEA ###
15 | .idea
16 | *.iws
17 | *.iml
18 | *.ipr
19 |
20 | ### NetBeans ###
21 | /nbproject/private/
22 | /nbbuild/
23 | /dist/
24 | /nbdist/
25 | /.nb-gradle/
26 | /build/
27 |
28 | ### VS Code ###
29 | .vscode/
30 |
--------------------------------------------------------------------------------
/src/main/resources/static/js/register.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | $("form").submit(check_data);
3 | $("input").focus(clear_error);
4 | });
5 |
6 | function check_data() {
7 | var pwd1 = $("#password").val();
8 | var pwd2 = $("#confirm-password").val();
9 | if(pwd1 != pwd2) {
10 | $("#confirm-password").addClass("is-invalid");
11 | return false;
12 | }
13 | return true;
14 | }
15 |
16 | function clear_error() {
17 | $(this).removeClass("is-invalid");
18 | }
--------------------------------------------------------------------------------
/src/main/resources/templates/mail/forget.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 牛客网-忘记密码
7 |
8 |
9 |
10 |
11 | xxx@xxx.com, 您好!
12 |
13 |
14 | 您正在找回牛客账号的密码, 本次操作的验证码为 u5s6dt ,
15 | 有效时间5分钟, 请您及时进行操作!
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/dao/CommentMapper.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.dao;
2 |
3 | import com.nowcoder.community.entity.Comment;
4 | import org.apache.ibatis.annotations.Mapper;
5 |
6 | import java.util.List;
7 |
8 | @Mapper
9 | public interface CommentMapper {
10 |
11 | List selectCommentsByEntity(int entityType, int entityId, int offset, int limit);
12 |
13 | int selectCountByEntity(int entityType, int entityId);
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/entity/Comment.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.entity;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.Date;
6 |
7 | /**
8 | * 评论
9 | */
10 | @Data
11 | public class Comment {
12 |
13 | private int id;
14 | private int userId;
15 | private int entityType;
16 | private int entityId;
17 | private int targetId;
18 | private String content;
19 | private int status;
20 | private Date createTime;
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/annotation/LoginRequired.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * 该注解表示是否需要登录
10 | */
11 | @Target(ElementType.METHOD) //作用在方法上
12 | @Retention(RetentionPolicy.RUNTIME) //运行时生效
13 | public @interface LoginRequired {
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/config/AlphaConfig.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 |
6 | import java.text.SimpleDateFormat;
7 |
8 | @Configuration
9 | public class AlphaConfig {
10 |
11 | @Bean
12 | public SimpleDateFormat simpleDateFormat() {
13 | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/resources/templates/mail/activation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 牛客网-激活账号
7 |
8 |
9 |
10 |
11 | , 您好!
12 |
13 |
14 | 您正在注册牛客网, 这是一封激活邮件, 请点击
15 | 此链接,
16 | 激活您的牛客账号!
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/main/resources/static/html/student.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 增加学生
6 |
7 |
8 |
9 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/main/resources/static/js/discuss.js:
--------------------------------------------------------------------------------
1 | function like(btn, entityType, entityId, entityUserId) {
2 | $.post(
3 | CONTEXT_PATH + "/like",
4 | {"entityType":entityType,"entityId":entityId,"entityUserId":entityUserId},
5 | function(data) {
6 | data = $.parseJSON(data);
7 | if(data.code == 0) {
8 | $(btn).children("i").text(data.likeCount);
9 | $(btn).children("b").text(data.likeStatus==1?'已赞':"赞");
10 | } else {
11 | alert(data.msg);
12 | }
13 | }
14 | );
15 | }
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/dao/UserMapper.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.dao;
2 |
3 | import com.nowcoder.community.entity.User;
4 | import org.apache.ibatis.annotations.Mapper;
5 |
6 | @Mapper
7 | public interface UserMapper {
8 |
9 | User selectById(int id);
10 |
11 | User selectByName(String username);
12 |
13 | User selectByEmail(String email);
14 |
15 | int insertUser(User user);
16 |
17 | int updateStatus(int id, int status);
18 |
19 | int updateHeader(int id, String headerUrl);
20 |
21 | int updatePassword(int id, String password);
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/utils/HostHolder.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.utils;
2 |
3 | import com.nowcoder.community.entity.User;
4 | import org.springframework.stereotype.Component;
5 |
6 | /**
7 | * 持有用户信息,用于代替session对象
8 | */
9 | @Component
10 | public class HostHolder {
11 |
12 | private ThreadLocal users = new ThreadLocal();
13 |
14 | public void setUser(User user){
15 | users.set(user);
16 | }
17 | public User getUser(){
18 | return users.get();
19 | }
20 |
21 | public void clear(){
22 | users.remove();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/dao/DiscussPostMapper.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.dao;
2 |
3 | import com.nowcoder.community.entity.DiscussPost;
4 | import org.apache.ibatis.annotations.Mapper;
5 | import org.apache.ibatis.annotations.Param;
6 |
7 | import java.util.List;
8 |
9 | @Mapper
10 | public interface DiscussPostMapper {
11 |
12 | List selectDiscussPosts(int userId, int offset, int limit);
13 |
14 | // @Param注解用于给参数取别名,
15 | // 如果只有一个参数,并且在里使用,则必须加别名.
16 | int selectDiscussPostRows(@Param("userId") int userId);
17 |
18 | int insertDiscussPost(DiscussPost discussPost);
19 | DiscussPost selectDiscussPostById(int id);
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/utils/CookieUtil.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.utils;
2 |
3 |
4 | import javax.servlet.http.Cookie;
5 | import javax.servlet.http.HttpServletRequest;
6 |
7 | public class CookieUtil {
8 | public static String getValue(HttpServletRequest request, String name){
9 | if(request == null || name == null){
10 | throw new IllegalArgumentException("参数为空!");
11 | }
12 |
13 | Cookie[] cookies = request.getCookies();
14 | if(cookies != null){
15 | for(Cookie cookie: cookies){
16 | if(cookie.getName().equals(name)){
17 | return cookie.getValue();
18 | }
19 | }
20 | }
21 | return null;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/dao/LoginTicketMapper.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.dao;
2 |
3 | import com.nowcoder.community.entity.LoginTicket;
4 | import org.apache.ibatis.annotations.*;
5 |
6 | @Mapper
7 | @Deprecated //废弃该组件
8 | public interface LoginTicketMapper {
9 |
10 | @Insert("insert into login_ticket(user_id,ticket,status,expired) " +
11 | "values" +
12 | "(#{userId},#{ticket},#{status},#{expired})"
13 | )
14 | @Options(useGeneratedKeys = true, keyProperty = "id")
15 | int insertLoinTicket(LoginTicket loginTicket);
16 |
17 | @Select("select * from login_ticket where ticket=#{ticket}")
18 | LoginTicket selectByTicket(String ticket);
19 |
20 | @Update("update login_ticket set status=#{status} where ticket=#{ticket}")
21 | int updateStatus(String ticket,int status); //更改凭证状态
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/service/CommentService.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.service;
2 |
3 | import com.nowcoder.community.dao.CommentMapper;
4 | import com.nowcoder.community.entity.Comment;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Service;
7 |
8 | import java.util.List;
9 |
10 | @Service
11 | public class CommentService {
12 |
13 | @Autowired
14 | private CommentMapper commentMapper;
15 |
16 | public List selectCommentsByEntity(int entityType, int entityId, int offset, int limit){
17 | return commentMapper.selectCommentsByEntity(entityType, entityId, offset, limit);
18 | }
19 |
20 | public int selectCountByEntity(int entityType, int entityId){
21 | return commentMapper.selectCountByEntity(entityType,entityId);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/com/nowcoder/community/SensitiveTest.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community;
2 |
3 | import com.nowcoder.community.utils.SensitiveFilter;
4 | import org.junit.Test;
5 | import org.junit.runner.RunWith;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.test.context.ContextConfiguration;
9 | import org.springframework.test.context.junit4.SpringRunner;
10 |
11 | @RunWith(SpringRunner.class)
12 | @SpringBootTest
13 | @ContextConfiguration(classes = CommunityApplication.class)
14 | public class SensitiveTest {
15 |
16 | @Autowired
17 | private SensitiveFilter sensitiveFilter;
18 |
19 | @Test
20 | public void testSensitiveFilter(){
21 | String text = "赌博 嫖 娼 哈哈哈 斗素数筛殴";
22 | text = sensitiveFilter.filter(text);
23 | System.out.println(text);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/resources/static/js/index.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | $("#publishBtn").click(publish);
3 | });
4 |
5 | function publish() {
6 | $("#publishModal").modal("hide");
7 |
8 | // 获取标题和内容
9 | var title = $("#recipient-name").val();
10 | var content = $("#message-text").val();
11 | // 发送异步请求(POST)
12 | $.post(
13 | CONTEXT_PATH + "/discuss/add",
14 | {"title":title,"content":content},
15 | function(data) {
16 | data = $.parseJSON(data);
17 | // 在提示框中显示返回消息
18 | $("#hintBody").text(data.msg);
19 | // 显示提示框
20 | $("#hintModal").modal("show");
21 | // 2秒后,自动隐藏提示框
22 | setTimeout(function(){
23 | $("#hintModal").modal("hide");
24 | // 刷新页面
25 | if(data.code == 0) {
26 | window.location.reload();
27 | }
28 | }, 2000);
29 | }
30 | );
31 |
32 | }
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/utils/CommunityConstant.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.utils;
2 |
3 | /**
4 | * 常量接口
5 | */
6 | public interface CommunityConstant {
7 | /**
8 | * 激活成功
9 | */
10 | int ACTIVATION_SUCCESS = 0;
11 |
12 | /**
13 | * 重复激活
14 | */
15 | int ACTIVATION_REPEAT = 1;
16 |
17 | /**
18 | * 激活失败
19 | */
20 | int ACTIVATION_FAILURE = 2;
21 |
22 | /**
23 | * 登录信息的默认超时时间,单位s
24 | */
25 | int DEFAULT_EXPIRED_SECONDS = 3600*12; //12个小时
26 |
27 | /**
28 | * 记住我后的超时时间,单位s
29 | */
30 | int REMEMBER_EXPIRED_SECONDS = 3600*24*100; //100天
31 |
32 | /**
33 | * 实体类型:帖子
34 | */
35 | int ENTITY_TYPE_POST = 1;
36 |
37 | /**
38 | * 实体类型:评论
39 | */
40 | int ENTITY_TYPE_COMMENT = 2;
41 |
42 | /**
43 | * 实体类型:用户
44 | */
45 | int ENTITY_TYPE_USER = 3;
46 | }
47 |
48 |
49 |
--------------------------------------------------------------------------------
/src/test/java/com/nowcoder/community/LoggerTests.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.test.context.ContextConfiguration;
9 | import org.springframework.test.context.junit4.SpringRunner;
10 |
11 | @RunWith(SpringRunner.class)
12 | @SpringBootTest
13 | @ContextConfiguration(classes = CommunityApplication.class)
14 | public class LoggerTests {
15 |
16 | private static final Logger logger = LoggerFactory.getLogger(LoggerTests.class);
17 |
18 | @Test
19 | public void testLogger() {
20 | System.out.println(logger.getName());
21 |
22 | logger.debug("debug log");
23 | logger.info("info log");
24 | logger.warn("warn log");
25 | logger.error("error log");
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/dao/MessageMapper.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.dao;
2 |
3 | import com.nowcoder.community.entity.Message;
4 | import org.apache.ibatis.annotations.Mapper;
5 |
6 | import java.util.List;
7 |
8 | @Mapper
9 | public interface MessageMapper {
10 |
11 | // 查询当前用户的会话列表,针对每个会话只返回一条最新的私信.
12 | List selectConversations(int userId, int offset, int limit);
13 |
14 | // 查询当前用户的会话数量.
15 | int selectConversationCount(int userId);
16 |
17 | // 查询某个会话所包含的私信列表.
18 | List selectLetters(String conversationId, int offset, int limit);
19 |
20 | // 查询某个会话所包含的私信数量.
21 | int selectLetterCount(String conversationId);
22 |
23 | // 查询未读私信的数量
24 | int selectLetterUnreadCount(int userId, String conversationId);
25 |
26 | // 新增消息
27 | int insertMessage(Message message);
28 |
29 | // 修改消息的状态
30 | int updateStatus(List ids, int status);
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/resources/static/html/ajax-demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AJAX
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
30 |
31 |
--------------------------------------------------------------------------------
/src/main/resources/static/js/letter.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | $("#sendBtn").click(send_letter);
3 | $(".close").click(delete_msg);
4 | });
5 |
6 | function send_letter() {
7 | $("#sendModal").modal("hide");
8 |
9 | var toName = $("#recipient-name").val();
10 | var content = $("#message-text").val();
11 | $.post(
12 | CONTEXT_PATH + "/letter/send",
13 | {"toName":toName,"content":content},
14 | function(data) {
15 | data = $.parseJSON(data);
16 | if(data.code == 0) {
17 | $("#hintBody").text("发送成功!");
18 | } else {
19 | $("#hintBody").text(data.msg);
20 | }
21 |
22 | $("#hintModal").modal("show");
23 | setTimeout(function(){
24 | $("#hintModal").modal("hide");
25 | location.reload();
26 | }, 2000);
27 | }
28 | );
29 | }
30 |
31 | function delete_msg() {
32 | // TODO 删除数据
33 | $(this).parents(".media").remove();
34 | }
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/service/AlphaService.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.service;
2 |
3 | import com.nowcoder.community.dao.AlphaDao;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.context.annotation.Scope;
6 | import org.springframework.stereotype.Service;
7 |
8 | import javax.annotation.PostConstruct;
9 | import javax.annotation.PreDestroy;
10 |
11 | @Service
12 | //@Scope("prototype")
13 | public class AlphaService {
14 |
15 | @Autowired
16 | private AlphaDao alphaDao;
17 |
18 | public AlphaService() {
19 | // System.out.println("实例化AlphaService");
20 | }
21 |
22 | @PostConstruct
23 | public void init() {
24 | // System.out.println("初始化AlphaService");
25 | }
26 |
27 | @PreDestroy
28 | public void destroy() {
29 | // System.out.println("销毁AlphaService");
30 | }
31 |
32 | public String find() {
33 | return alphaDao.select();
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/resources/static/js/profile.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | $(".follow-btn").click(follow);
3 | });
4 |
5 | function follow() {
6 | var btn = this;
7 | if($(btn).hasClass("btn-info")) {
8 | // 关注TA
9 | $.post(
10 | CONTEXT_PATH + "/follow",
11 | {"entityType":3,"entityId":$(btn).prev().val()},
12 | function(data) {
13 | data = $.parseJSON(data);
14 | if(data.code == 0) {
15 | window.location.reload();
16 | } else {
17 | alert(data.msg);
18 | }
19 | }
20 | );
21 | // $(btn).text("已关注").removeClass("btn-info").addClass("btn-secondary");
22 | } else {
23 | // 取消关注
24 | $.post(
25 | CONTEXT_PATH + "/unfollow",
26 | {"entityType":3,"entityId":$(btn).prev().val()},
27 | function(data) {
28 | data = $.parseJSON(data);
29 | if(data.code == 0) {
30 | window.location.reload();
31 | } else {
32 | alert(data.msg);
33 | }
34 | }
35 | );
36 | //$(btn).text("关注TA").removeClass("btn-secondary").addClass("btn-info");
37 | }
38 | }
--------------------------------------------------------------------------------
/src/main/resources/mapper/comment-mapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | id,user_id,entity_type,entity_id,target_id,content,status,create_time
9 |
10 |
11 |
20 |
21 |
28 |
--------------------------------------------------------------------------------
/src/main/resources/static/js/global.js:
--------------------------------------------------------------------------------
1 | var CONTEXT_PATH = "/community";
2 |
3 | window.alert = function(message) {
4 | if(!$(".alert-box").length) {
5 | $("body").append(
6 | ''+
7 | '
'+
8 | '
'+
9 | ''+
15 | '
'+
18 | ''+
21 | '
'+
22 | '
'+
23 | '
'
24 | );
25 | }
26 |
27 | var h = $(".alert-box").height();
28 | var y = h / 2 - 100;
29 | if(h > 600) y -= 100;
30 | $(".alert-box .modal-dialog").css("margin", (y < 0 ? 0 : y) + "px auto");
31 |
32 | $(".alert-box .modal-body p").text(message);
33 | $(".alert-box").modal("show");
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/config/WebMvcConfig.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.config;
2 |
3 | import com.nowcoder.community.config.interceptor.LoginRequiredInterceptor;
4 | import com.nowcoder.community.config.interceptor.LoginTicketInterceptor;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
9 |
10 | @Configuration
11 | public class WebMvcConfig implements WebMvcConfigurer {
12 |
13 | @Autowired
14 | private LoginTicketInterceptor loginTicketInterceptor;
15 |
16 | @Autowired
17 | private LoginRequiredInterceptor loginRequiredInterceptor;
18 | @Override
19 | public void addInterceptors(InterceptorRegistry registry) {
20 | registry.addInterceptor(loginTicketInterceptor)
21 | .excludePathPatterns("/**/*.css","/**/*.js","/**/*.png","/**/*.jpg","/**/*.jpeg");
22 |
23 | registry.addInterceptor(loginRequiredInterceptor)
24 | .excludePathPatterns("/**/*.css","/**/*.js","/**/*.png","/**/*.jpg","/**/*.jpeg");
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/config/RedisConfig.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.data.redis.connection.RedisConnectionFactory;
6 | import org.springframework.data.redis.core.RedisTemplate;
7 | import org.springframework.data.redis.serializer.RedisSerializer;
8 |
9 | /**
10 | * Redis序列化
11 | */
12 | @Configuration
13 | public class RedisConfig {
14 |
15 | @Bean
16 | public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
17 | RedisTemplate template = new RedisTemplate<>();
18 | template.setConnectionFactory(factory);
19 |
20 | // 设置key的序列化方式
21 | template.setKeySerializer(RedisSerializer.string());
22 | // 设置value的序列化方式
23 | template.setValueSerializer(RedisSerializer.json());
24 | // 设置hash的key的序列化方式
25 | template.setHashKeySerializer(RedisSerializer.string());
26 | // 设置hash的value的序列化方式
27 | template.setHashValueSerializer(RedisSerializer.json());
28 |
29 | template.afterPropertiesSet();
30 | return template;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/aspect/AlphaAspect.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.aspect;
2 |
3 | import org.aspectj.lang.ProceedingJoinPoint;
4 | import org.aspectj.lang.annotation.*;
5 | import org.springframework.stereotype.Component;
6 |
7 | //@Component
8 | //@Aspect
9 | public class AlphaAspect {
10 |
11 | @Pointcut("execution(* com.nowcoder.community.service.*.*(..))")
12 | public void pointcut() {
13 |
14 | }
15 |
16 | @Before("pointcut()")
17 | public void before() {
18 | System.out.println("before");
19 | }
20 |
21 | @After("pointcut()")
22 | public void after() {
23 | System.out.println("after");
24 | }
25 |
26 | @AfterReturning("pointcut()")
27 | public void afterRetuning() {
28 | System.out.println("afterRetuning");
29 | }
30 |
31 | @AfterThrowing("pointcut()")
32 | public void afterThrowing() {
33 | System.out.println("afterThrowing");
34 | }
35 |
36 | @Around("pointcut()")
37 | public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
38 | System.out.println("around before");
39 | Object obj = joinPoint.proceed();
40 | System.out.println("around after");
41 | return obj;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/com/nowcoder/community/MailTest.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community;
2 |
3 | import com.nowcoder.community.utils.MailClient;
4 | import net.bytebuddy.asm.Advice;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.boot.test.context.SpringBootTest;
9 | import org.springframework.test.context.ContextConfiguration;
10 | import org.springframework.test.context.junit4.SpringRunner;
11 | import org.thymeleaf.TemplateEngine;
12 | import org.thymeleaf.context.Context;
13 |
14 | @RunWith(SpringRunner.class)
15 | @SpringBootTest
16 | @ContextConfiguration(classes = CommunityApplication.class)
17 | public class MailTest {
18 |
19 | @Autowired
20 | private MailClient mailClient;
21 |
22 | @Autowired
23 | private TemplateEngine templateEngine;
24 |
25 | @Test
26 | public void testTextMail(){
27 | mailClient.sendMail("306698601@qq.com","test","emailtest");
28 | }
29 |
30 | /**
31 | * 发送html邮件
32 | */
33 | @Test
34 | public void testHtmlMail(){
35 | Context context = new Context();
36 | context.setVariable("username","sandy");
37 |
38 | String content = templateEngine.process("/mail/demo", context);
39 | mailClient.sendMail("306698601@qq.com","test",content);
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/config/KaptchaConfig.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.config;
2 |
3 | import com.google.code.kaptcha.Producer;
4 | import com.google.code.kaptcha.impl.DefaultKaptcha;
5 | import com.google.code.kaptcha.util.Config;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 |
9 | import java.util.*;
10 |
11 | @Configuration
12 | public class KaptchaConfig {
13 |
14 | @Bean
15 | public Producer kaptchaProducer(){
16 | Properties properties = new Properties();
17 | //验证码
18 | properties.setProperty("kaptcha.image.width","100"); //长度
19 | properties.setProperty("kaptcha.image.height","40"); //高度
20 | properties.setProperty("kaptcha.textproducer.font.size","32"); //字体大小
21 | properties.setProperty("kaptcha.textproducer.font.color","0,0,0"); //颜色
22 | properties.setProperty("kaptcha.textproducer.char.string","0123456789qwertyuioplkjhgfdszxcvbnm"); //随机字
23 | properties.setProperty("kaptcha.textproducer.char.length","4"); //长度
24 | properties.setProperty("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise"); //干扰
25 |
26 | DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
27 | Config config = new Config(properties);
28 | defaultKaptcha.setConfig(config);
29 | return defaultKaptcha;
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/utils/MailClient.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.utils;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.beans.factory.annotation.Value;
7 | import org.springframework.mail.javamail.JavaMailSender;
8 | import org.springframework.mail.javamail.MimeMessageHelper;
9 | import org.springframework.stereotype.Component;
10 |
11 | import javax.mail.MessagingException;
12 | import javax.mail.internet.MimeMessage;
13 |
14 | @Component
15 | public class MailClient {
16 | private static final Logger logger = LoggerFactory.getLogger(MailClient.class);
17 |
18 | @Autowired
19 | private JavaMailSender mailSender;
20 |
21 | @Value("${spring.mail.username}")
22 | private String from;
23 |
24 | public void sendMail(String to,String subject,String content){
25 | try {
26 | MimeMessage message = mailSender.createMimeMessage();
27 | MimeMessageHelper helper = new MimeMessageHelper(message);
28 | helper.setFrom(from);
29 | helper.setTo(to);
30 | helper.setSubject(subject);
31 | helper.setText(content,true); //允许支持html文本
32 | mailSender.send(helper.getMimeMessage());
33 | } catch (MessagingException e) {
34 | logger.error("发送邮件失败:"+e.getMessage());
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/config/interceptor/LoginRequiredInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.config.interceptor;
2 |
3 | import com.nowcoder.community.annotation.LoginRequired;
4 | import com.nowcoder.community.utils.HostHolder;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 | import org.springframework.web.method.HandlerMethod;
8 | import org.springframework.web.servlet.HandlerInterceptor;
9 |
10 | import javax.servlet.http.HttpServletRequest;
11 | import javax.servlet.http.HttpServletResponse;
12 | import java.lang.reflect.Method;
13 |
14 | @Component
15 | public class LoginRequiredInterceptor implements HandlerInterceptor {
16 | @Autowired
17 | private HostHolder hostHolder;
18 |
19 |
20 | @Override
21 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
22 | if(handler instanceof HandlerMethod){ //判断拦截目标是否是一个方法
23 | HandlerMethod handlerMethod = (HandlerMethod)handler;
24 | Method method = handlerMethod.getMethod();
25 | LoginRequired annotation = method.getAnnotation(LoginRequired.class);
26 | if(annotation != null && hostHolder.getUser() == null){ //注解不为空拦截的方法需要登录才能实现,hostHolder.geUser()为空表示当前没有用户登录
27 | response.sendRedirect(request.getContextPath()+"/login");
28 | return false;
29 | }
30 | }
31 | return true;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/utils/CommunityUtil.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.utils;
2 |
3 |
4 | import com.alibaba.fastjson.JSONObject;
5 | import org.apache.commons.lang3.StringUtils;
6 | import org.springframework.util.DigestUtils;
7 |
8 | import java.util.Map;
9 | import java.util.UUID;
10 |
11 | public class CommunityUtil {
12 |
13 | // 生成随机字符串
14 | public static String generateUUID(){
15 | return UUID.randomUUID().toString().replaceAll("-","");
16 | }
17 |
18 | // MD5加密
19 | //真实密码+盐 --md5--> 加密密码
20 | //盐:随机字符串
21 | public static String md5(String key){
22 | if(StringUtils.isBlank(key)) return null;
23 |
24 | return DigestUtils.md5DigestAsHex(key.getBytes());
25 | }
26 |
27 | /**
28 | * 将浏览器返回的数据转成json字符串
29 | * @param code 响应码
30 | * @param msg 响应信息
31 | * @param map 业务信息
32 | * @return
33 | */
34 | public static String getJsonString (int code, String msg, Map map){
35 | JSONObject json = new JSONObject();
36 | json.put("code",code);
37 | json.put("msg",msg);
38 | if(map != null){
39 | for(String key: map.keySet()){
40 | json.put(key,map.get(key));
41 | }
42 | }
43 |
44 | return json.toJSONString();
45 | }
46 | public static String getJsonString (int code, String msg){
47 | return getJsonString(code, msg, null);
48 | }
49 | public static String getJsonString (int code){
50 | return getJsonString(code, null, null);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/controller/advice/ExceptionAdvice.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.controller.advice;
2 |
3 | import com.nowcoder.community.utils.CommunityUtil;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.stereotype.Controller;
7 | import org.springframework.web.bind.annotation.ControllerAdvice;
8 | import org.springframework.web.bind.annotation.ExceptionHandler;
9 |
10 | import javax.servlet.http.HttpServletRequest;
11 | import javax.servlet.http.HttpServletResponse;
12 | import java.io.IOException;
13 | import java.io.PrintWriter;
14 |
15 | @ControllerAdvice(annotations = Controller.class)
16 | public class ExceptionAdvice {
17 |
18 | private static final Logger logger = LoggerFactory.getLogger(ExceptionAdvice.class);
19 |
20 | @ExceptionHandler({Exception.class})
21 | public void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException {
22 | logger.error("服务器发生异常: " + e.getMessage());
23 | for (StackTraceElement element : e.getStackTrace()) {
24 | logger.error(element.toString());
25 | }
26 |
27 | String xRequestedWith = request.getHeader("x-requested-with"); //获取请求方式,同步/异步
28 | if ("XMLHttpRequest".equals(xRequestedWith)) { //异步
29 | response.setContentType("application/plain;charset=utf-8");
30 | PrintWriter writer = response.getWriter();
31 | writer.write(CommunityUtil.getJsonString(1, "服务器异常!"));
32 | } else {
33 | response.sendRedirect(request.getContextPath() + "/error");
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/resources/mapper/discusspost-mapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | id, user_id, title, content, type, status, create_time, comment_count, score
9 |
10 |
11 |
12 | user_id, title, content, type, status, create_time, comment_count, score
13 |
14 |
15 |
25 |
26 |
34 |
35 |
40 |
41 |
42 | insert into discuss_post()
43 | values (#{userId},#{title},#{content},#{type},#{status},#{createTime},#{commentCount},#{score})
44 |
45 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/controller/LikeController.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.controller;
2 |
3 | import com.nowcoder.community.annotation.LoginRequired;
4 | import com.nowcoder.community.entity.User;
5 | import com.nowcoder.community.service.LikeService;
6 | import com.nowcoder.community.utils.CommunityUtil;
7 | import com.nowcoder.community.utils.HostHolder;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.stereotype.Controller;
10 | import org.springframework.web.bind.annotation.RequestMapping;
11 | import org.springframework.web.bind.annotation.RequestMethod;
12 | import org.springframework.web.bind.annotation.ResponseBody;
13 |
14 | import java.util.HashMap;
15 | import java.util.Map;
16 |
17 | @Controller
18 | public class LikeController {
19 |
20 | @Autowired
21 | private LikeService likeService;
22 |
23 | @Autowired
24 | private HostHolder hostHolder;
25 |
26 | @RequestMapping(path = "/like", method = RequestMethod.POST)
27 | @ResponseBody
28 | @LoginRequired
29 | public String like(int entityType, int entityId, int entityUserId){
30 | User user = hostHolder.getUser();
31 |
32 | //实现点赞
33 | likeService.like(user.getId(),entityType,entityId,entityUserId);
34 | //数量
35 | long entityLikeCount = likeService.findEntityLikeCount(entityType, entityId);
36 | //状态
37 | int entityLikeStatus = likeService.findEntityLikeStatus(user.getId(), entityType, entityId);
38 |
39 | //返回结果
40 | Map map = new HashMap<>();
41 | map.put("likeCount",entityLikeCount);
42 | map.put("likeStatus",entityLikeStatus);
43 |
44 | return CommunityUtil.getJsonString(0,null,map);
45 |
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/service/DiscussPostService.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.service;
2 |
3 | import com.nowcoder.community.dao.DiscussPostMapper;
4 | import com.nowcoder.community.entity.DiscussPost;
5 | import com.nowcoder.community.utils.SensitiveFilter;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.stereotype.Service;
8 | import org.springframework.web.util.HtmlUtils;
9 |
10 | import java.util.List;
11 |
12 | @Service
13 | public class DiscussPostService {
14 |
15 | @Autowired
16 | private DiscussPostMapper discussPostMapper;
17 |
18 | @Autowired
19 | private SensitiveFilter sensitiveFilter;
20 |
21 | public List findDiscussPosts(int userId, int offset, int limit) {
22 | return discussPostMapper.selectDiscussPosts(userId, offset, limit);
23 | }
24 |
25 | public int findDiscussPostRows(int userId) {
26 | return discussPostMapper.selectDiscussPostRows(userId);
27 | }
28 |
29 | public int addDiscussPost(DiscussPost discussPost){
30 | if(discussPost == null){
31 | throw new IllegalArgumentException("参数不能为空!");
32 | }
33 | //标题内容去标签
34 | discussPost.setTitle(HtmlUtils.htmlEscape(discussPost.getTitle()));
35 | discussPost.setContent(HtmlUtils.htmlEscape(discussPost.getContent()));
36 | //过滤敏感词
37 | discussPost.setTitle(sensitiveFilter.filter(discussPost.getTitle()));
38 | discussPost.setContent(sensitiveFilter.filter(discussPost.getContent()));
39 |
40 | return discussPostMapper.insertDiscussPost(discussPost);
41 | }
42 |
43 | public DiscussPost findDiscussPostById(int id){
44 | return discussPostMapper.selectDiscussPostById(id);
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/aspect/ServiceLogAspect.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.aspect;
2 |
3 | import org.aspectj.lang.JoinPoint;
4 | import org.aspectj.lang.annotation.Aspect;
5 | import org.aspectj.lang.annotation.Before;
6 | import org.aspectj.lang.annotation.Pointcut;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.stereotype.Component;
10 | import org.springframework.web.context.request.RequestContextHolder;
11 | import org.springframework.web.context.request.ServletRequestAttributes;
12 |
13 | import javax.servlet.http.HttpServletRequest;
14 | import java.text.SimpleDateFormat;
15 | import java.util.Date;
16 |
17 | @Component
18 | @Aspect
19 | public class ServiceLogAspect {
20 |
21 | private static final Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);
22 |
23 | /**
24 | * 对业务层逻辑统一记录日志
25 | */
26 | @Pointcut("execution(* com.nowcoder.community.service.*.*(..))") //切点作用范围
27 | public void pointcut() {
28 |
29 | }
30 |
31 | /**
32 | * 前置通知
33 | * @param joinPoint 连接的目标
34 | */
35 | @Before("pointcut()")
36 | public void before(JoinPoint joinPoint) {
37 | // 用户[1.2.3.4],在[xxx],访问了[com.nowcoder.community.service.xxx()].
38 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
39 | HttpServletRequest request = attributes.getRequest(); //获取request对象
40 | String ip = request.getRemoteHost();
41 | String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
42 | String target = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(); //组件名+方法名
43 | logger.info(String.format("用户[%s],在[%s],访问了[%s].", ip, now, target));
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/resources/mapper/user-mapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | username, password, salt, email, type, status, activation_code, header_url, create_time
9 |
10 |
11 |
12 | id, username, password, salt, email, type, status, activation_code, header_url, create_time
13 |
14 |
15 |
20 |
21 |
26 |
27 |
32 |
33 |
34 | insert into user ()
35 | values(#{username}, #{password}, #{salt}, #{email}, #{type}, #{status}, #{activationCode}, #{headerUrl}, #{createTime})
36 |
37 |
38 |
39 | update user set status = #{status} where id = #{id}
40 |
41 |
42 |
45 |
46 |
47 | update user set password = #{password} where id = #{id}
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/service/MessageService.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.service;
2 |
3 | import com.nowcoder.community.dao.MessageMapper;
4 | import com.nowcoder.community.entity.Message;
5 | import com.nowcoder.community.utils.SensitiveFilter;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.stereotype.Service;
8 | import org.springframework.web.util.HtmlUtils;
9 |
10 | import java.util.List;
11 |
12 | @Service
13 | public class MessageService {
14 |
15 | @Autowired
16 | private MessageMapper messageMapper;
17 |
18 | @Autowired
19 | private SensitiveFilter sensitiveFilter;
20 |
21 | public List findConversations(int userId, int offset, int limit) {
22 | return messageMapper.selectConversations(userId, offset, limit);
23 | }
24 |
25 | public int findConversationCount(int userId) {
26 | return messageMapper.selectConversationCount(userId);
27 | }
28 |
29 | public List findLetters(String conversationId, int offset, int limit) {
30 | return messageMapper.selectLetters(conversationId, offset, limit);
31 | }
32 |
33 | public int findLetterCount(String conversationId) {
34 | return messageMapper.selectLetterCount(conversationId);
35 | }
36 |
37 | public int findLetterUnreadCount(int userId, String conversationId) {
38 | return messageMapper.selectLetterUnreadCount(userId, conversationId);
39 | }
40 |
41 | public int addMessage(Message message) {
42 | message.setContent(HtmlUtils.htmlEscape(message.getContent()));
43 | message.setContent(sensitiveFilter.filter(message.getContent()));
44 | return messageMapper.insertMessage(message);
45 | }
46 |
47 | public int readMessage(List ids) {
48 | return messageMapper.updateStatus(ids, 1);
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/utils/RedisKeyUtil.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.utils;
2 |
3 | public class RedisKeyUtil {
4 |
5 | private static final String SPLIT = ":";
6 | private static final String PREFIX_ENTITY_LIKE = "like:entity";
7 | private static final String PREFIX_USER_LIKE = "like:user";
8 | private static final String PREFIX_FOLLOWEE = "followee";
9 | private static final String PREFIX_FOLLOWER = "follower";
10 | private static final String PREFIX_KAPTCHA = "kaptcha";
11 | private static final String PREFIX_TICKET = "ticket";
12 | private static final String PREFIX_USER = "user";
13 |
14 | //某个实体的赞
15 | //like:entity:entityType:entityId->set(userId)
16 | public static String getEntityLikeKey(int entityType, int entityId){
17 | return PREFIX_ENTITY_LIKE+SPLIT+entityType+SPLIT+entityId;
18 | }
19 |
20 | //某个用户的赞
21 | public static String getUserLikeKey(int userId){
22 | return PREFIX_USER_LIKE+SPLIT+userId;
23 | }
24 |
25 |
26 | //某个用户关注的实体
27 | //followee:userId:entityType->zset(entityId,nowTime)
28 | public static String getFolloweeKey(int userId, int entityType){
29 | return PREFIX_FOLLOWEE+SPLIT+userId+SPLIT+entityType;
30 | }
31 |
32 | //某个用户拥有的粉丝
33 | //follower:entityType:entityId->zset(userId,nowTime)
34 | public static String getFollowerKey(int entityType, int entityId){
35 | return PREFIX_FOLLOWER+SPLIT+entityType+SPLIT+entityId;
36 | }
37 |
38 | //验证码key
39 | public static String getKaptchaKey(String owner){
40 | return PREFIX_KAPTCHA+SPLIT+owner;
41 | }
42 |
43 | //登录凭证key
44 | public static String getTicketKey(String ticket){
45 | return PREFIX_TICKET+SPLIT+ticket;
46 | }
47 |
48 | //用户key
49 | public static String getUserKey(int userId){
50 | return PREFIX_USER+SPLIT+userId;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/entity/Page.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.entity;
2 |
3 | /**
4 | * 封装分页相关的信息.
5 | */
6 | public class Page {
7 |
8 | // 当前页码
9 | private int current = 1;
10 | // 显示上限
11 | private int limit = 10;
12 | // 数据总数(用于计算总页数)
13 | private int rows;
14 | // 查询路径(用于复用分页链接)
15 | private String path;
16 |
17 | public int getCurrent() {
18 | return current;
19 | }
20 |
21 | public void setCurrent(int current) {
22 | if (current >= 1) {
23 | this.current = current;
24 | }
25 | }
26 |
27 | public int getLimit() {
28 | return limit;
29 | }
30 |
31 | public void setLimit(int limit) {
32 | if (limit >= 1 && limit <= 100) {
33 | this.limit = limit;
34 | }
35 | }
36 |
37 | public int getRows() {
38 | return rows;
39 | }
40 |
41 | public void setRows(int rows) {
42 | if (rows >= 0) {
43 | this.rows = rows;
44 | }
45 | }
46 |
47 | public String getPath() {
48 | return path;
49 | }
50 |
51 | public void setPath(String path) {
52 | this.path = path;
53 | }
54 |
55 | /**
56 | * 获取当前页的起始行
57 | *
58 | * @return
59 | */
60 | public int getOffset() {
61 | // current * limit - limit
62 | return (current - 1) * limit;
63 | }
64 |
65 | /**
66 | * 获取总页数
67 | *
68 | * @return
69 | */
70 | public int getTotal() {
71 | // rows / limit [+1]
72 | if (rows % limit == 0) {
73 | return rows / limit;
74 | } else {
75 | return rows / limit + 1;
76 | }
77 | }
78 |
79 | /**
80 | * 获取起始页码
81 | *
82 | * @return
83 | */
84 | public int getFrom() {
85 | int from = current - 2;
86 | return from < 1 ? 1 : from;
87 | }
88 |
89 | /**
90 | * 获取结束页码
91 | *
92 | * @return
93 | */
94 | public int getTo() {
95 | int to = current + 2;
96 | int total = getTotal();
97 | return to > total ? total : to;
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/resources/static/css/global.css:
--------------------------------------------------------------------------------
1 | html {
2 | height: 100%;
3 | }
4 |
5 | body {
6 | background: #eee;
7 | font-family: arial, STHeiti, 'Microsoft YaHei', \5b8b\4f53;
8 | font-size: 14px;
9 | height: 100%;
10 | }
11 |
12 | .nk-container {
13 | position: relative;
14 | height: auto;
15 | min-height: 100%;
16 | }
17 |
18 | .container {
19 | width: 960px;
20 | padding: 0;
21 | }
22 |
23 | header .navbar-brand {
24 | background: url('http://static.nowcoder.com/images/res/logo/logo-v3.png') no-repeat;
25 | background-size: 147px 42px;
26 | width: 147px;
27 | height: 42px;
28 | margin: 5px 15px 5px 0;
29 | }
30 |
31 | header .navbar {
32 | padding: 5px 0;
33 | font-size: 16px;
34 | }
35 |
36 | header .badge {
37 | position: absolute;
38 | top: -3px;
39 | left: 33px;
40 | }
41 |
42 | footer {
43 | padding: 20px 0;
44 | font-size: 12px;
45 | position: absolute;
46 | bottom: 0;
47 | width: 100%;
48 | }
49 |
50 | footer .qrcode {
51 | text-align: center;
52 | }
53 |
54 | footer .detail-info{
55 | border-left: 1px solid #888;
56 | }
57 |
58 | footer .company-info li {
59 | padding-left: 16px;
60 | margin: 4px 0;
61 | }
62 |
63 | .main {
64 | padding: 20px 0;
65 | padding-bottom: 200px;
66 | }
67 |
68 | .main .container {
69 | background: #fff;
70 | padding: 20px;
71 | }
72 |
73 | i {
74 | font-style: normal;
75 | }
76 |
77 | u {
78 | text-decoration: none;
79 | }
80 |
81 | b {
82 | font-weight: normal;
83 | }
84 |
85 | a {
86 | color: #000;
87 | }
88 |
89 | a:hover {
90 | text-decoration: none;
91 | }
92 |
93 | .font-size-12 {
94 | font-size: 12px;
95 | }
96 | .font-size-14 {
97 | font-size: 14px;
98 | }
99 | .font-size-16 {
100 | font-size: 16px;
101 | }
102 | .font-size-18 {
103 | font-size: 18px;
104 | }
105 | .font-size-20 {
106 | font-size: 20px;
107 | }
108 | .font-size-22 {
109 | font-size: 20px;
110 | }
111 | .font-size-24 {
112 | font-size: 20px;
113 | }
114 |
115 | .hidden {
116 | display: none;
117 | }
118 |
119 | .rt-0 {
120 | right: 0;
121 | top: 0;
122 | }
123 |
124 | .square {
125 | display: inline-block;
126 | width: 7px;
127 | height: 7px;
128 | background: #ff6547;
129 | margin-bottom: 2px;
130 | margin-right: 3px;
131 | }
132 |
133 | .bg-gray {
134 | background: #eff0f2;
135 | }
136 |
137 | .user-header {
138 | width: 50px;
139 | height: 50px;
140 | }
141 |
142 | em {
143 | font-style: normal;
144 | color: red;
145 | }
146 |
--------------------------------------------------------------------------------
/src/main/java/com/nowcoder/community/controller/HomeController.java:
--------------------------------------------------------------------------------
1 | package com.nowcoder.community.controller;
2 |
3 | import com.nowcoder.community.entity.DiscussPost;
4 | import com.nowcoder.community.entity.Page;
5 | import com.nowcoder.community.entity.User;
6 | import com.nowcoder.community.service.DiscussPostService;
7 | import com.nowcoder.community.service.LikeService;
8 | import com.nowcoder.community.service.UserService;
9 | import com.nowcoder.community.utils.CommunityConstant;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.stereotype.Controller;
12 | import org.springframework.ui.Model;
13 | import org.springframework.web.bind.annotation.RequestMapping;
14 | import org.springframework.web.bind.annotation.RequestMethod;
15 |
16 | import java.util.ArrayList;
17 | import java.util.HashMap;
18 | import java.util.List;
19 | import java.util.Map;
20 |
21 | @Controller
22 | public class HomeController implements CommunityConstant {
23 |
24 | @Autowired
25 | private DiscussPostService discussPostService;
26 |
27 | @Autowired
28 | private UserService userService;
29 |
30 | @Autowired
31 | private LikeService likeService;
32 |
33 | @RequestMapping(path = "/index", method = RequestMethod.GET)
34 | public String getIndexPage(Model model, Page page) {
35 | // 方法调用钱,SpringMVC会自动实例化Model和Page,并将Page注入Model.
36 | // 所以,在thymeleaf中可以直接访问Page对象中的数据.
37 | page.setRows(discussPostService.findDiscussPostRows(0));
38 | page.setPath("/index");
39 |
40 | List list = discussPostService.findDiscussPosts(0, page.getOffset(), page.getLimit());
41 | List