├── .deepsource.toml
├── .gitignore
├── .mvn
└── wrapper
│ ├── MavenWrapperDownloader.java
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── allen
│ │ └── moments
│ │ └── v2
│ │ ├── MomentsApplication.java
│ │ ├── aop
│ │ ├── ExceptionHandler.java
│ │ └── LoggingHandler.java
│ │ ├── api
│ │ ├── AuthController.java
│ │ ├── PostController.java
│ │ └── UserController.java
│ │ ├── dao
│ │ ├── CommentDao.java
│ │ ├── CommentSqlProvider.java
│ │ ├── PostDao.java
│ │ ├── PostSqlProvider.java
│ │ ├── UserDao.java
│ │ └── UserSqlProvider.java
│ │ ├── interceptors
│ │ ├── AuthInterceptor.java
│ │ └── InterceptorConfig.java
│ │ ├── model
│ │ ├── Comment.java
│ │ ├── DML.java
│ │ ├── ErrorType.java
│ │ ├── Like.java
│ │ ├── Photo.java
│ │ ├── Post.java
│ │ └── User.java
│ │ ├── redis
│ │ ├── RedisConfig.java
│ │ └── RedisUtil.java
│ │ ├── service
│ │ ├── AuthService.java
│ │ ├── PostService.java
│ │ ├── S3Service.java
│ │ └── UserService.java
│ │ └── utils
│ │ ├── ApplicationException.java
│ │ ├── JsonResult.java
│ │ ├── JwtUtil.java
│ │ ├── S3Client.java
│ │ ├── ThreadPoolManager.java
│ │ ├── annotations
│ │ ├── PassToken.java
│ │ └── RequireToken.java
│ │ └── error_handler
│ │ └── DBExceptionChecker.java
└── resources
│ ├── META-INF
│ └── additional-spring-configuration-metadata.json
│ ├── log4j2.xml
│ └── mybatis-generator-config.xml
└── test
└── java
└── com
└── allen
└── moments
└── v2
└── MomentsApplicationTests.java
/.deepsource.toml:
--------------------------------------------------------------------------------
1 | version = 1
2 |
3 | [[analyzers]]
4 | name = "java"
5 | enabled = true
6 |
7 | [analyzers.meta]
8 | runtime_version = "8"
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 | /src/main/resources/application.properties
7 | /src/main/resources/mybatis-generator-config.xml
8 |
9 | ### STS ###
10 | .apt_generated
11 | .classpath
12 | .factorypath
13 | .project
14 | .settings
15 | .springBeans
16 | .sts4-cache
17 |
18 | ### IntelliJ IDEA ###
19 | .idea
20 | *.iws
21 | *.iml
22 | *.ipr
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
--------------------------------------------------------------------------------
/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2007-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | import java.net.*;
18 | import java.io.*;
19 | import java.nio.channels.*;
20 | import java.util.Properties;
21 |
22 | public class MavenWrapperDownloader {
23 |
24 | private static final String WRAPPER_VERSION = "0.5.6";
25 | /**
26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
27 | */
28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
30 |
31 | /**
32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
33 | * use instead of the default one.
34 | */
35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
36 | ".mvn/wrapper/maven-wrapper.properties";
37 |
38 | /**
39 | * Path where the maven-wrapper.jar will be saved to.
40 | */
41 | private static final String MAVEN_WRAPPER_JAR_PATH =
42 | ".mvn/wrapper/maven-wrapper.jar";
43 |
44 | /**
45 | * Name of the property which should be used to override the default download url for the wrapper.
46 | */
47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
48 |
49 | public static void main(String args[]) {
50 | System.out.println("- Downloader started");
51 | File baseDirectory = new File(args[0]);
52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
53 |
54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom
55 | // wrapperUrl parameter.
56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
57 | String url = DEFAULT_DOWNLOAD_URL;
58 | if (mavenWrapperPropertyFile.exists()) {
59 | FileInputStream mavenWrapperPropertyFileInputStream = null;
60 | try {
61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
62 | Properties mavenWrapperProperties = new Properties();
63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
65 | } catch (IOException e) {
66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
67 | } finally {
68 | try {
69 | if (mavenWrapperPropertyFileInputStream != null) {
70 | mavenWrapperPropertyFileInputStream.close();
71 | }
72 | } catch (IOException e) {
73 | // Ignore ...
74 | }
75 | }
76 | }
77 | System.out.println("- Downloading from: " + url);
78 |
79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
80 | if (!outputFile.getParentFile().exists()) {
81 | if (!outputFile.getParentFile().mkdirs()) {
82 | System.out.println(
83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
84 | }
85 | }
86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
87 | try {
88 | downloadFileFromURL(url, outputFile);
89 | System.out.println("Done");
90 | System.exit(0);
91 | } catch (Throwable e) {
92 | System.out.println("- Error downloading");
93 | e.printStackTrace();
94 | System.exit(1);
95 | }
96 | }
97 |
98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception {
99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
100 | String username = System.getenv("MVNW_USERNAME");
101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
102 | Authenticator.setDefault(new Authenticator() {
103 | @Override
104 | protected PasswordAuthentication getPasswordAuthentication() {
105 | return new PasswordAuthentication(username, password);
106 | }
107 | });
108 | }
109 | URL website = new URL(urlString);
110 | ReadableByteChannel rbc;
111 | rbc = Channels.newChannel(website.openStream());
112 | FileOutputStream fos = new FileOutputStream(destination);
113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
114 | fos.close();
115 | rbc.close();
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AllenSun-HM/moments_v2_backend/6314021a343fbabfd880bf8a73916f014d8ee481/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # moments_v2_backend (Work In Progress)
2 | backend for a sharing app using SpringBoot, Redis, MySQL, and AWS S3.
3 |
4 | This is the second version of my project [ShareOurDays](https://github.com/AllenSun-HM/ShareOurDays)'s backend. I added more features like getting most-popular users or posts.
5 | I built this project while learning and using SpringBoot, Redis, and MySQL.
6 |
7 | ### Highlights
8 | 1. applied AOP in exception handling, logging, and access control, which substansively removed redundant code.
9 | 2. integrated multithreading and thread pool to take advantage of mutil-core CPU.
10 | 3. added cache layer using Redis to enhance performance
11 | 4. used MyBatis to achieve ORM
12 | ### How to Maintain the Consistency between MySQL and Redis?
13 | #### Query Data Process
14 | .png)
15 | ### Delete Data Process
16 | .png)
17 | ### Insert/Update Data Process
18 | .png)
19 |
20 | ### TODOS
21 | 1. add ElasticSearch for user & post searching feature;
22 | 2. configure MySQL clusters to separate db-read and db-write to MySQL master node and slave node;
23 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # https://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Mingw, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | fi
118 |
119 | if [ -z "$JAVA_HOME" ]; then
120 | javaExecutable="`which javac`"
121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
122 | # readlink(1) is not available as standard on Solaris 10.
123 | readLink=`which readlink`
124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
125 | if $darwin ; then
126 | javaHome="`dirname \"$javaExecutable\"`"
127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
128 | else
129 | javaExecutable="`readlink -f \"$javaExecutable\"`"
130 | fi
131 | javaHome="`dirname \"$javaExecutable\"`"
132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
133 | JAVA_HOME="$javaHome"
134 | export JAVA_HOME
135 | fi
136 | fi
137 | fi
138 |
139 | if [ -z "$JAVACMD" ] ; then
140 | if [ -n "$JAVA_HOME" ] ; then
141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
142 | # IBM's JDK on AIX uses strange locations for the executables
143 | JAVACMD="$JAVA_HOME/jre/sh/java"
144 | else
145 | JAVACMD="$JAVA_HOME/bin/java"
146 | fi
147 | else
148 | JAVACMD="`which java`"
149 | fi
150 | fi
151 |
152 | if [ ! -x "$JAVACMD" ] ; then
153 | echo "Error: JAVA_HOME is not defined correctly." >&2
154 | echo " We cannot execute $JAVACMD" >&2
155 | exit 1
156 | fi
157 |
158 | if [ -z "$JAVA_HOME" ] ; then
159 | echo "Warning: JAVA_HOME environment variable is not set."
160 | fi
161 |
162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
163 |
164 | # traverses directory structure from process work directory to filesystem root
165 | # first directory with .mvn subdirectory is considered project base directory
166 | find_maven_basedir() {
167 |
168 | if [ -z "$1" ]
169 | then
170 | echo "Path not specified to find_maven_basedir"
171 | return 1
172 | fi
173 |
174 | basedir="$1"
175 | wdir="$1"
176 | while [ "$wdir" != '/' ] ; do
177 | if [ -d "$wdir"/.mvn ] ; then
178 | basedir=$wdir
179 | break
180 | fi
181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
182 | if [ -d "${wdir}" ]; then
183 | wdir=`cd "$wdir/.."; pwd`
184 | fi
185 | # end of workaround
186 | done
187 | echo "${basedir}"
188 | }
189 |
190 | # concatenates all lines of a file
191 | concat_lines() {
192 | if [ -f "$1" ]; then
193 | echo "$(tr -s '\n' ' ' < "$1")"
194 | fi
195 | }
196 |
197 | BASE_DIR=`find_maven_basedir "$(pwd)"`
198 | if [ -z "$BASE_DIR" ]; then
199 | exit 1;
200 | fi
201 |
202 | ##########################################################################################
203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
204 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
205 | ##########################################################################################
206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
207 | if [ "$MVNW_VERBOSE" = true ]; then
208 | echo "Found .mvn/wrapper/maven-wrapper.jar"
209 | fi
210 | else
211 | if [ "$MVNW_VERBOSE" = true ]; then
212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
213 | fi
214 | if [ -n "$MVNW_REPOURL" ]; then
215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
216 | else
217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
218 | fi
219 | while IFS="=" read key value; do
220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
221 | esac
222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
223 | if [ "$MVNW_VERBOSE" = true ]; then
224 | echo "Downloading from: $jarUrl"
225 | fi
226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
227 | if $cygwin; then
228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
229 | fi
230 |
231 | if command -v wget > /dev/null; then
232 | if [ "$MVNW_VERBOSE" = true ]; then
233 | echo "Found wget ... using wget"
234 | fi
235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
236 | wget "$jarUrl" -O "$wrapperJarPath"
237 | else
238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
239 | fi
240 | elif command -v curl > /dev/null; then
241 | if [ "$MVNW_VERBOSE" = true ]; then
242 | echo "Found curl ... using curl"
243 | fi
244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
245 | curl -o "$wrapperJarPath" "$jarUrl" -f
246 | else
247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
248 | fi
249 |
250 | else
251 | if [ "$MVNW_VERBOSE" = true ]; then
252 | echo "Falling back to using Java to download"
253 | fi
254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
255 | # For Cygwin, switch paths to Windows format before running javac
256 | if $cygwin; then
257 | javaClass=`cygpath --path --windows "$javaClass"`
258 | fi
259 | if [ -e "$javaClass" ]; then
260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
261 | if [ "$MVNW_VERBOSE" = true ]; then
262 | echo " - Compiling MavenWrapperDownloader.java ..."
263 | fi
264 | # Compiling the Java class
265 | ("$JAVA_HOME/bin/javac" "$javaClass")
266 | fi
267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
268 | # Running the downloader
269 | if [ "$MVNW_VERBOSE" = true ]; then
270 | echo " - Running MavenWrapperDownloader.java ..."
271 | fi
272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
273 | fi
274 | fi
275 | fi
276 | fi
277 | ##########################################################################################
278 | # End of extension
279 | ##########################################################################################
280 |
281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
282 | if [ "$MVNW_VERBOSE" = true ]; then
283 | echo $MAVEN_PROJECTBASEDIR
284 | fi
285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
286 |
287 | # For Cygwin, switch paths to Windows format before running java
288 | if $cygwin; then
289 | [ -n "$M2_HOME" ] &&
290 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
291 | [ -n "$JAVA_HOME" ] &&
292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
293 | [ -n "$CLASSPATH" ] &&
294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
295 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
297 | fi
298 |
299 | # Provide a "standardized" way to retrieve the CLI args that will
300 | # work with both Windows and non-Windows executions.
301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
302 | export MAVEN_CMD_LINE_ARGS
303 |
304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
305 |
306 | exec "$JAVACMD" \
307 | $MAVEN_OPTS \
308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
311 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM https://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM set title of command window
39 | title %0
40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
42 |
43 | @REM set %HOME% to equivalent of $HOME
44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
45 |
46 | @REM Execute a user defined script before this one
47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
51 | :skipRcPre
52 |
53 | @setlocal
54 |
55 | set ERROR_CODE=0
56 |
57 | @REM To isolate internal variables from possible post scripts, we use another setlocal
58 | @setlocal
59 |
60 | @REM ==== START VALIDATION ====
61 | if not "%JAVA_HOME%" == "" goto OkJHome
62 |
63 | echo.
64 | echo Error: JAVA_HOME not found in your environment. >&2
65 | echo Please set the JAVA_HOME variable in your environment to match the >&2
66 | echo location of your Java installation. >&2
67 | echo.
68 | goto error
69 |
70 | :OkJHome
71 | if exist "%JAVA_HOME%\bin\java.exe" goto init
72 |
73 | echo.
74 | echo Error: JAVA_HOME is set to an invalid directory. >&2
75 | echo JAVA_HOME = "%JAVA_HOME%" >&2
76 | echo Please set the JAVA_HOME variable in your environment to match the >&2
77 | echo location of your Java installation. >&2
78 | echo.
79 | goto error
80 |
81 | @REM ==== END VALIDATION ====
82 |
83 | :init
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
122 |
123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
124 |
125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
127 | )
128 |
129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
131 | if exist %WRAPPER_JAR% (
132 | if "%MVNW_VERBOSE%" == "true" (
133 | echo Found %WRAPPER_JAR%
134 | )
135 | ) else (
136 | if not "%MVNW_REPOURL%" == "" (
137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
138 | )
139 | if "%MVNW_VERBOSE%" == "true" (
140 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
141 | echo Downloading from: %DOWNLOAD_URL%
142 | )
143 |
144 | powershell -Command "&{"^
145 | "$webclient = new-object System.Net.WebClient;"^
146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
148 | "}"^
149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
150 | "}"
151 | if "%MVNW_VERBOSE%" == "true" (
152 | echo Finished downloading %WRAPPER_JAR%
153 | )
154 | )
155 | @REM End of extension
156 |
157 | @REM Provide a "standardized" way to retrieve the CLI args that will
158 | @REM work with both Windows and non-Windows executions.
159 | set MAVEN_CMD_LINE_ARGS=%*
160 |
161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
162 | if ERRORLEVEL 1 goto error
163 | goto end
164 |
165 | :error
166 | set ERROR_CODE=1
167 |
168 | :end
169 | @endlocal & set ERROR_CODE=%ERROR_CODE%
170 |
171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
175 | :skipRcPost
176 |
177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
179 |
180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
181 |
182 | exit /B %ERROR_CODE%
183 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.4.4
9 |
10 |
11 | com.allen
12 | MomentsV2
13 | 0.0.2-SNAPSHOT
14 | moments_app_v2
15 | a project that builds a website for daily sharing
16 |
17 | 1.8
18 | 1.3.2
19 |
20 |
21 |
22 | repository.spring.release
23 | Spring GA Repository
24 | https://repo.spring.io/plugins-release/
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-data-jdbc
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-logging
35 |
36 |
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-starter-data-redis
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-starter-logging
45 |
46 |
47 |
48 |
49 | org.apache.commons
50 | commons-pool2
51 |
52 |
53 | org.springframework.boot
54 | spring-boot-starter-jdbc
55 |
56 |
57 | org.springframework.boot
58 | spring-boot-starter-web
59 |
60 |
61 | org.springframework.boot
62 | spring-boot-starter-logging
63 |
64 |
65 |
66 |
67 | org.springframework.boot
68 | spring-boot-devtools
69 | runtime
70 | true
71 |
72 |
73 | mysql
74 | mysql-connector-java
75 | runtime
76 |
77 |
78 | org.springframework.boot
79 | spring-boot-starter-test
80 | test
81 |
82 |
83 | com.alibaba
84 | druid
85 | 1.0.5
86 |
87 |
88 |
89 | org.mybatis.spring.boot
90 | mybatis-spring-boot-starter
91 | 1.3.2
92 |
93 |
94 | org.mybatis.generator
95 | mybatis-generator-core
96 | ${mybatis.generator.version}
97 |
98 |
99 | com.auth0
100 | java-jwt
101 | 3.4.0
102 |
103 |
104 | com.alibaba
105 | fastjson
106 | 1.2.37
107 |
108 |
109 | junit
110 | junit
111 |
112 |
113 |
114 | com.amazonaws
115 | aws-java-sdk-s3
116 | 1.11.327
117 |
118 |
119 | com.amazonaws
120 | aws-java-sdk-dynamodb
121 | 1.11.327
122 |
123 |
124 |
125 | org.springframework.boot
126 | spring-boot-starter-aop
127 |
128 |
129 |
130 |
131 | org.springframework.boot
132 | spring-boot-starter-log4j2
133 |
134 |
135 |
136 | org.jetbrains
137 | annotations
138 | 13.0
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 | org.springframework.boot
147 | spring-boot-maven-plugin
148 | 2.1.5.RELEASE
149 |
150 |
151 | org.mybatis.generator
152 | mybatis-generator-maven-plugin
153 | 1.3.6
154 |
155 | src/main/resources/mybatis-generator-config.xml
156 | true
157 | true
158 | true
159 |
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/MomentsApplication.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2;
2 |
3 | import org.mybatis.spring.annotation.MapperScan;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 |
7 | @SpringBootApplication()
8 | @MapperScan("com.allen.moments.v2.dao")
9 | public class MomentsApplication {
10 | public static void main(String[] args) {
11 | SpringApplication.run(MomentsApplication.class, args);
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/aop/ExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.aop;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.allen.moments.v2.utils.ApplicationException;
5 | import com.allen.moments.v2.utils.JsonResult;
6 | import org.aspectj.lang.JoinPoint;
7 | import org.aspectj.lang.annotation.AfterThrowing;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | public class ExceptionHandler {
12 |
13 | private Logger logger = LoggerFactory.getLogger(this.getClass());
14 |
15 | @AfterThrowing(pointcut = "execution(public * com.allen.moments.v2.api.*.*(..))", throwing="e")
16 | public JsonResult> doAfterThrowing(JoinPoint joinPoint, Throwable e) {
17 | try {
18 | logger.error("------->Error Class:" + e.getClass().getName());
19 | logger.error("------->Error msg:" + e.getMessage());
20 | logger.error("------->Error method:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
21 | Object[] arguments = joinPoint.getArgs();
22 | if (arguments != null && arguments.length > 0) {
23 | for ( int i = 0; i < arguments.length; i++) {
24 | logger.error("------->args[" + i + "]: " + JSONObject.toJSONString(arguments[i]));
25 | }
26 | }
27 | if (e.getClass() == ApplicationException.class) { // customized exception with err_no and message
28 | return JsonResult.failure(((ApplicationException) e).getErrNo(), e.getMessage());
29 | }
30 | return JsonResult.unknownFailure();
31 | } catch (Exception ex) {
32 | logger.error("------->exception occured!");
33 | logger.error("------->exception message:{}", ex.getMessage());
34 | return JsonResult.unknownFailure();
35 | }
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/aop/LoggingHandler.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.aop;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import org.apache.logging.log4j.LogManager;
5 | import org.apache.logging.log4j.Logger;
6 | import org.aspectj.lang.JoinPoint;
7 | import org.aspectj.lang.annotation.*;
8 | import org.springframework.stereotype.Component;
9 |
10 |
11 | @Aspect
12 | @Component
13 | public class LoggingHandler {
14 |
15 | private final Logger logger = LogManager.getLogger(this.getClass());
16 |
17 | /**
18 | *
19 | */
20 | @Before(value = "execution(public * com.allen.moments.v2.api.*.*(..))")
21 | public void before(JoinPoint joinPoint) {
22 | String className = joinPoint.getTarget().getClass().getName();
23 | String methodName = joinPoint.getSignature().getName();
24 | Object[] args = joinPoint.getArgs();
25 | logger.info("class " + className + "'s " + methodName + " has parameter(s):" + JSONObject.toJSONString(args));
26 | }
27 |
28 | /**
29 | * after method return, print returned value
30 | */
31 | @AfterReturning(value = "execution(public * com.allen.moments.v2.api.*.*(..))", returning = "returnVal")
32 | public void afterReturning(JoinPoint joinPoint, Object returnVal) {
33 | String className = joinPoint.getTarget().getClass().getName();
34 | String methodName = joinPoint.getSignature().getName();
35 | logger.info("class " + className + "'s " + methodName + " returns: " + returnVal.toString());
36 | }
37 |
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/api/AuthController.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.api;
2 |
3 | import com.allen.moments.v2.model.User;
4 | import com.allen.moments.v2.service.AuthService;
5 | import com.allen.moments.v2.utils.JsonResult;
6 | import com.allen.moments.v2.utils.JwtUtil;
7 | import com.allen.moments.v2.utils.annotations.PassToken;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.web.bind.annotation.PostMapping;
10 | import org.springframework.web.bind.annotation.RequestBody;
11 | import org.springframework.web.bind.annotation.RequestMapping;
12 | import org.springframework.web.bind.annotation.RestController;
13 |
14 | import javax.servlet.http.HttpServletRequest;
15 | import java.util.HashMap;
16 |
17 | @RestController
18 | @RequestMapping("/api/v1/login")
19 | public class AuthController {
20 |
21 | private final AuthService authService;
22 | private final JwtUtil jwtUtil;
23 |
24 | @Autowired
25 | public AuthController(AuthService authService, JwtUtil jwtUtil) {
26 | this.authService = authService;
27 | this.jwtUtil = jwtUtil;
28 | }
29 |
30 |
31 | @PassToken
32 | @PostMapping("")
33 | public JsonResult> login(HttpServletRequest request, @RequestBody String email, @RequestBody String password) {
34 | String token = request.getHeader("token");
35 | if (token != null) {
36 | return JsonResult.failure(100002, "user already logged in");
37 | }
38 | try {
39 | User user = authService.login(email, password);
40 | token = this.jwtUtil.getToken(user.getUid());
41 | HashMap data = new HashMap<>();
42 | data.put("token", token);
43 | data.put("user_info", user);
44 | return JsonResult.successWithData(data);
45 | }
46 | catch (RuntimeException exception) {
47 | exception.printStackTrace();
48 | return JsonResult.failure(100003, exception.getMessage());
49 | }
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/api/PostController.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.api;
2 |
3 | import com.allen.moments.v2.model.Post;
4 | import com.allen.moments.v2.service.PostService;
5 | import com.allen.moments.v2.service.S3Service;
6 | import com.allen.moments.v2.utils.JsonResult;
7 | import com.allen.moments.v2.utils.annotations.RequireToken;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.web.bind.annotation.*;
10 | import org.springframework.web.multipart.MultipartFile;
11 | import org.springframework.dao.*;
12 | import javax.servlet.http.HttpServletRequest;
13 | import javax.servlet.http.HttpServletResponse;
14 | import java.util.HashMap;
15 | import java.util.List;
16 |
17 |
18 | @RestController
19 | @RequestMapping("/api/v1/post")
20 | public class PostController {
21 | private final PostService postService;
22 | private final S3Service s3Service;
23 |
24 | @Autowired
25 | public PostController(PostService postService, S3Service s3Service) {
26 | this.postService = postService;
27 | this.s3Service = s3Service;
28 | }
29 |
30 | @PostMapping()
31 | @RequireToken
32 | public JsonResult> addPost(HttpServletRequest request, @RequestBody String text, @RequestBody List photos) {
33 | int uid = (Integer) request.getAttribute("logged_uid");
34 | try {
35 | int postId;
36 | if (photos != null && photos.size() > 0) { // photos are uploaded
37 | List photoUrls = s3Service.upload(photos);
38 | postId = postService.addPostWithPhotos(uid, text, photoUrls);
39 | } else { // no photos uploaded
40 | postId = postService.addPost(uid, text);
41 | }
42 | HashMap result = new HashMap<>();
43 | result.put("post_id", postId);
44 | return JsonResult.successWithData(result);
45 | }
46 | catch (Exception exception) {
47 | return JsonResult.failure(200001, "post upload failed");
48 | }
49 | }
50 |
51 | @PostMapping("/like/{postId}")
52 | @RequireToken
53 | public JsonResult> likePost(HttpServletRequest request, HttpServletResponse response, @PathVariable("postId") Integer postId) {
54 | int uid = (Integer) request.getAttribute("logged_uid");
55 | JsonResult> result;
56 | try {
57 | if (postId == null) {
58 | throw new Exception("illegal query parameter");
59 | }
60 | if (postService.likeOrUnlike(true, uid, postId)) {
61 | return JsonResult.success();
62 | }
63 | else return JsonResult.unknownFailure();
64 | }
65 | catch (Exception exception) {
66 | if (exception.getClass() == DuplicateKeyException.class) {
67 | return JsonResult.failure(200003, "aleady liked this post");
68 | }
69 | return JsonResult.failure(200009, exception.getMessage());
70 | }
71 | }
72 |
73 | @GetMapping("like/{#postId}")
74 | @RequireToken()
75 | public JsonResult> getUidsWhoLikedThis(@PathVariable("postId") Integer postId, @RequestParam Integer start, @RequestParam Integer limit) {
76 | if (postId == null || start == null || limit == null) {
77 | return JsonResult.failure(200010, "illegal query parameter");
78 | }
79 | if (limit > 200) {
80 | return JsonResult.failure(200011, "query range is too big");
81 | }
82 | return JsonResult.successWithData(postService.getUsersWhoLikedPosts(postId, start, limit));
83 | }
84 |
85 | @DeleteMapping("/like/{postId}")
86 | @RequireToken
87 | public JsonResult> UnlikePost(HttpServletRequest request, HttpServletResponse response, @PathVariable("postId") Integer postId) {
88 | int uid = (Integer) request.getAttribute("logged_uid");
89 | JsonResult> result;
90 | try {
91 | if (postId == null) {
92 | throw new Exception("illegal query parameter");
93 | }
94 | if (postService.likeOrUnlike(false, uid, postId)) {
95 | return JsonResult.success();
96 | }
97 | else return JsonResult.unknownFailure();
98 | }
99 | catch (Exception exception) {
100 | return JsonResult.failure(200003, exception.getMessage());
101 | }
102 | }
103 |
104 | @PostMapping("/comment/{postId}")
105 | @RequireToken
106 | public JsonResult> addComment(HttpServletRequest request, HttpServletResponse response, @PathVariable("postId") Integer postId, @RequestBody String comment) {
107 | int uid = (Integer) request.getAttribute("logged_uid");
108 | JsonResult> result;
109 | try {
110 | if (postId == null || comment == null) {
111 | throw new Exception("illegal query parameter");
112 | }
113 | if (postService.addComment(uid, postId, comment)) {
114 | return JsonResult.success();
115 | }
116 | else return JsonResult.unknownFailure();
117 | }
118 | catch (Exception exception) {
119 | return JsonResult.failure(200003, exception.getMessage());
120 | }
121 | }
122 |
123 | @DeleteMapping("/comment/{postId}/{commentId}")
124 | @RequireToken
125 | public JsonResult> removeComment(HttpServletRequest request, HttpServletResponse response, @PathVariable("commentId") Integer commentId) {
126 | int uid = (Integer) request.getAttribute("logged_uid");
127 | JsonResult> result;
128 | try {
129 | if (commentId == null) {
130 | throw new Exception("illegal query parameter");
131 | }
132 | if (postService.deleteComment(commentId, uid)) {
133 | return JsonResult.success();
134 | }
135 | else return JsonResult.unknownFailure();
136 | }
137 | catch (Exception exception) {
138 | return JsonResult.failure(200003, exception.getMessage());
139 | }
140 | }
141 |
142 | @GetMapping("/{postId}")
143 | @RequireToken
144 | public JsonResult> getPost(@PathVariable("postId") int postId) {
145 | Post post = postService.getPost(postId);
146 | JsonResult result;
147 | if (post != null) {
148 | post.setJsonPhotoUrls(null);
149 | return JsonResult.successWithData(post);
150 | }
151 | return JsonResult.failure(200002, "no post found");
152 | }
153 |
154 | @GetMapping("/rank/like_count")
155 | @RequireToken
156 | public JsonResult> getPostsWithHighestLikeCounts(@RequestParam Integer start, @RequestParam Integer limit) {
157 | if (start == null || limit == null) {
158 | return JsonResult.failure(200010, "illegal query parameter");
159 | }
160 | List posts = postService.getPostsWithHighestLikeCounts(start, limit);
161 | if (posts == null) {
162 | return JsonResult.failure(400001, "no more posts");
163 | }
164 | return JsonResult.successWithData(posts);
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/api/UserController.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.api;
2 |
3 | import com.allen.moments.v2.model.User;
4 | import com.allen.moments.v2.service.S3Service;
5 | import com.allen.moments.v2.service.UserService;
6 | import com.allen.moments.v2.utils.JsonResult;
7 | import com.allen.moments.v2.utils.JwtUtil;
8 | import com.allen.moments.v2.utils.annotations.RequireToken;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.web.bind.annotation.*;
11 | import org.springframework.web.multipart.MultipartFile;
12 |
13 |
14 | import javax.servlet.http.HttpServletRequest;
15 | import java.util.List;
16 |
17 | /**
18 | * handle user info CRUD
19 | *
20 | */
21 | @RestController
22 | @RequestMapping("/api/v1/user")
23 | @RequireToken
24 | public class UserController {
25 | private final UserService userService;
26 | private final S3Service s3Service;
27 | private final JwtUtil jwtUtil;
28 |
29 | @Autowired
30 | public UserController(UserService userService, S3Service s3Service, JwtUtil jwtUtil) {
31 | this.userService = userService;
32 | this.s3Service = s3Service;
33 | this.jwtUtil = jwtUtil;
34 | }
35 |
36 | private int getLoggedUid(HttpServletRequest request) {
37 | return (int) request.getAttribute("logged_uid");
38 | }
39 |
40 | @PostMapping("/register")
41 | @RequireToken
42 | public JsonResult> register(@RequestBody String name, @RequestBody String email, @RequestBody int sex, @RequestBody int age, @RequestBody String password) throws Exception {
43 | User addedUser = userService.addUser(email, name, sex, age, password);
44 | String token = jwtUtil.getToken(addedUser.getUid());
45 | return JsonResult.successWithData(token);
46 | }
47 |
48 |
49 | @GetMapping("/{id}")
50 | @RequireToken
51 | public JsonResult> getUserById(@PathVariable("id") int uid) {
52 | User user = userService.getUser(uid);
53 | if (user == null) {
54 | return JsonResult.failure(40001, "user does not exist");
55 | }
56 | return JsonResult.successWithData(user);
57 | }
58 |
59 | @PostMapping("/password")
60 | @RequireToken
61 | public JsonResult> setNewPassword(HttpServletRequest request, @RequestParam("old_passwd") String oldPassword, @RequestParam("new_passwd") String newPassword) throws Exception {
62 | int uid = (int) request.getAttribute("loggedUid");
63 | userService.setNewPassword(uid, oldPassword, newPassword);
64 | return JsonResult.success();
65 | }
66 |
67 | @GetMapping("/get_all")
68 | @RequireToken
69 | public List showAllUsers() {
70 | return userService.getAllUsers();
71 | }
72 |
73 | @PostMapping("/follow")
74 | @RequireToken
75 | public JsonResult> follow(HttpServletRequest request, @RequestParam("uid_to_follow") int uidToFollow) {
76 | int uidOfFollowed = this.getLoggedUid(request);
77 | userService.follow(uidOfFollowed, uidToFollow);
78 | return JsonResult.success();
79 | }
80 |
81 | @GetMapping("/{id}/followers")
82 | @RequireToken
83 | public JsonResult> getFollowers(@PathVariable("id") int uid) {
84 | return JsonResult.successWithData(userService.getFollowersId(uid));
85 | }
86 |
87 | @GetMapping("/{id}/followings")
88 | @RequireToken
89 | public JsonResult> getFollowings(@PathVariable("id") int uid) {
90 | return JsonResult.successWithData(userService.getFollowingsId(uid));
91 | }
92 |
93 | @DeleteMapping("/unfollow/{id}")
94 | @RequireToken
95 | public JsonResult> unfollow(HttpServletRequest request, @PathVariable("id") int followedId) throws Exception {
96 | int uidOfFollower = this.getLoggedUid(request);
97 | userService.unfollow(followedId, uidOfFollower);
98 | return JsonResult.success();
99 | }
100 |
101 | @GetMapping("/rank/follower")
102 | @RequireToken
103 | public JsonResult> getPopularUsers(HttpServletRequest request, @RequestParam int start, @RequestParam int limit) throws Exception {
104 | return JsonResult.successWithData(userService.selectUsersOrderByFollowerCounts(start, limit));
105 | }
106 |
107 | @PostMapping("/avatar")
108 | @RequireToken
109 | public JsonResult> setCustomizedAvatar(HttpServletRequest request, @RequestBody MultipartFile avatar) throws Exception {
110 | int uid = this.getLoggedUid(request);
111 | String avatarURI = s3Service.upload(avatar);
112 | userService.addCustomizedAvatar(uid, avatarURI);
113 | return JsonResult.successWithData(avatarURI);
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/dao/CommentDao.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.dao;
2 |
3 | import com.allen.moments.v2.model.Comment;
4 | import org.apache.ibatis.annotations.Delete;
5 | import org.apache.ibatis.annotations.Insert;
6 | import org.apache.ibatis.annotations.InsertProvider;
7 | import org.apache.ibatis.annotations.Result;
8 | import org.apache.ibatis.annotations.Results;
9 | import org.apache.ibatis.annotations.Select;
10 | import org.apache.ibatis.annotations.Update;
11 | import org.apache.ibatis.annotations.UpdateProvider;
12 | import org.apache.ibatis.type.JdbcType;
13 |
14 | public interface CommentDao {
15 | @Delete({
16 | "delete from post_comment",
17 | "where comment_id = #{commentId,jdbcType=INTEGER}"
18 | })
19 | int deleteByPrimaryKey(Integer commentId);
20 |
21 | @Insert({
22 | "insert into post_comment (comment_id, postid, ",
23 | "comment, commentedBy)",
24 | "values (#{commentId,jdbcType=INTEGER}, #{postid,jdbcType=INTEGER}, ",
25 | "#{comment,jdbcType=VARCHAR}, #{commentedby,jdbcType=INTEGER})"
26 | })
27 | int insert(Comment record);
28 |
29 | @InsertProvider(type=CommentSqlProvider.class, method="insertSelective")
30 | int insertSelective(Comment record);
31 |
32 | @Select({
33 | "select",
34 | "comment_id, postid, comment, commentedBy",
35 | "from post_comment",
36 | "where comment_id = #{commentId,jdbcType=INTEGER}"
37 | })
38 | @Results({
39 | @Result(column="comment_id", property="commentId", jdbcType=JdbcType.INTEGER, id=true),
40 | @Result(column="postid", property="postid", jdbcType=JdbcType.INTEGER),
41 | @Result(column="comment", property="comment", jdbcType=JdbcType.VARCHAR),
42 | @Result(column="commentedBy", property="commentedby", jdbcType=JdbcType.INTEGER)
43 | })
44 | Comment selectByPrimaryKey(Integer commentId);
45 |
46 | @UpdateProvider(type=CommentSqlProvider.class, method="updateByPrimaryKeySelective")
47 | int updateByPrimaryKeySelective(Comment record);
48 |
49 | @Update({
50 | "update post_comment",
51 | "set postid = #{postid,jdbcType=INTEGER},",
52 | "comment = #{comment,jdbcType=VARCHAR},",
53 | "commentedBy = #{commentedby,jdbcType=INTEGER}",
54 | "where comment_id = #{commentId,jdbcType=INTEGER}"
55 | })
56 | int updateByPrimaryKey(Comment record);
57 | }
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/dao/CommentSqlProvider.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.dao;
2 |
3 | import com.allen.moments.v2.model.Comment;
4 | import org.apache.ibatis.jdbc.SQL;
5 |
6 | public class CommentSqlProvider {
7 |
8 | public String insertSelective(Comment record) {
9 | SQL sql = new SQL();
10 | sql.INSERT_INTO("post_comment");
11 |
12 | if (record.getCommentId() != null) {
13 | sql.VALUES("comment_id", "#{commentId,jdbcType=INTEGER}");
14 | }
15 |
16 | if (record.getPostid() != null) {
17 | sql.VALUES("postid", "#{postid,jdbcType=INTEGER}");
18 | }
19 |
20 | if (record.getComment() != null) {
21 | sql.VALUES("comment", "#{comment,jdbcType=VARCHAR}");
22 | }
23 |
24 | if (record.getCommentedby() != null) {
25 | sql.VALUES("commentedBy", "#{commentedby,jdbcType=INTEGER}");
26 | }
27 |
28 | return sql.toString();
29 | }
30 |
31 | public String updateByPrimaryKeySelective(Comment record) {
32 | SQL sql = new SQL();
33 | sql.UPDATE("post_comment");
34 |
35 | if (record.getPostid() != null) {
36 | sql.SET("postid = #{postid,jdbcType=INTEGER}");
37 | }
38 |
39 | if (record.getComment() != null) {
40 | sql.SET("comment = #{comment,jdbcType=VARCHAR}");
41 | }
42 |
43 | if (record.getCommentedby() != null) {
44 | sql.SET("commentedBy = #{commentedby,jdbcType=INTEGER}");
45 | }
46 |
47 | sql.WHERE("comment_id = #{commentId,jdbcType=INTEGER}");
48 |
49 | return sql.toString();
50 | }
51 | }
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/dao/PostDao.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.dao;
2 |
3 | import com.allen.moments.v2.model.Post;
4 | import org.apache.ibatis.annotations.Delete;
5 | import org.apache.ibatis.annotations.Insert;
6 | import org.apache.ibatis.annotations.InsertProvider;
7 | import org.apache.ibatis.annotations.Result;
8 | import org.apache.ibatis.annotations.Results;
9 | import org.apache.ibatis.annotations.Select;
10 | import org.apache.ibatis.annotations.Update;
11 | import org.apache.ibatis.annotations.UpdateProvider;
12 | import org.apache.ibatis.type.JdbcType;
13 | import org.springframework.stereotype.Repository;
14 |
15 | import java.util.List;
16 |
17 | @Repository
18 | public interface PostDao {
19 | @Delete({
20 | "delete from post",
21 | "where postid = #{postid,jdbcType=INTEGER}"
22 | })
23 | int deleteByPrimaryKey(Integer postid);
24 |
25 | @Insert({
26 | "insert into post (postid, text, ",
27 | "posted_by, time_created, ",
28 | "like_count, photo)",
29 | "values (#{postid,jdbcType=INTEGER}, #{text,jdbcType=VARCHAR}, ",
30 | "#{postedBy,jdbcType=INTEGER}, #{timeCreated,jdbcType=TIMESTAMP}, ",
31 | "#{likeCount,jdbcType=INTEGER}, #{jsonPhotoUrls,jdbcType=LONGVARCHAR})"
32 | })
33 | int insert(Post record);
34 |
35 | @InsertProvider(type=PostSqlProvider.class, method="insertSelective")
36 | int insertSelective(Post record);
37 |
38 | @Select({
39 | "select",
40 | "postid, text, posted_by, time_created, like_count, photo",
41 | "from post",
42 | "where postid = #{postid,jdbcType=INTEGER}"
43 | })
44 | @Results({
45 | @Result(column="postid", property="postid", jdbcType=JdbcType.INTEGER, id=true),
46 | @Result(column="text", property="text", jdbcType=JdbcType.VARCHAR),
47 | @Result(column="posted_by", property="postedBy", jdbcType=JdbcType.INTEGER),
48 | @Result(column="time_created", property="timeCreated", jdbcType=JdbcType.TIMESTAMP),
49 | @Result(column="like_count", property="likeCount", jdbcType=JdbcType.INTEGER),
50 | @Result(column="photo", property="jsonPhotoUrls", jdbcType=JdbcType.LONGVARCHAR)
51 | })
52 | Post selectByPrimaryKey(Integer postid);
53 |
54 | @Select({
55 | "SELECT",
56 | "postid, text, posted_by, time_created, like_count, photo",
57 | "FROM post",
58 | "ORDER BY like_count DESC",
59 | "LIMIT #{start, jdbcType =INTEGER}, #{limit, jdbcType=INTEGER}"
60 | })
61 | @Results({
62 | @Result(column="postid", property="postid", jdbcType=JdbcType.INTEGER, id=true),
63 | @Result(column="text", property="text", jdbcType=JdbcType.VARCHAR),
64 | @Result(column="posted_by", property="postedBy", jdbcType=JdbcType.INTEGER),
65 | @Result(column="time_created", property="timeCreated", jdbcType=JdbcType.TIMESTAMP),
66 | @Result(column="like_count", property="likeCount", jdbcType=JdbcType.INTEGER),
67 | @Result(column="photo", property="jsonPhotoUrls", jdbcType=JdbcType.LONGVARCHAR)
68 | })
69 | List getPostsWithHighestLikeCounts(int start, int limit);
70 |
71 |
72 | @UpdateProvider(type=PostSqlProvider.class, method="updateByPrimaryKeySelective")
73 | int updateByPrimaryKeySelective(Post record);
74 |
75 | // @Update({
76 | // "update post",
77 | // "set text = #{text,jdbcType=VARCHAR},",
78 | // "posted_by = #{postedBy,jdbcType=INTEGER},",
79 | // "time_created = #{timeCreated,jdbcType=TIMESTAMP},",
80 | // "like_count = #{likeCount,jdbcType=INTEGER},",
81 | // "photo = #{jsonPhotoUrls,jdbcType=LONGVARCHAR}",
82 | // "where postid = #{postid,jdbcType=INTEGER}"
83 | // })
84 | // int updateByPrimaryKeyWithBLOBs(Post record);
85 | //
86 | // @Update({
87 | // "update post",
88 | // "set text = #{text,jdbcType=VARCHAR},",
89 | // "posted_by = #{postedBy,jdbcType=INTEGER},",
90 | // "time_created = #{timeCreated,jdbcType=TIMESTAMP},",
91 | // "like_count = #{likeCount,jdbcType=INTEGER}",
92 | // "where postid = #{postid,jdbcType=INTEGER}"
93 | // })
94 | // int updateByPrimaryKey(Post record);
95 |
96 |
97 | @Select({
98 | "SELECT max(postid)",
99 | "FROM post"
100 | })
101 | int selectMaxPostId();
102 |
103 | @Insert({
104 | "INSERT INTO post_likes",
105 | "(postid, like_by)",
106 | "VALUES (#{postId,jdbcType=INTEGER}, #{uid,jdbcType=INTEGER})",
107 | })
108 | int insertLikeRecord(int uid, int postId);
109 |
110 | @Delete({
111 | "DELETE FROM post_likes",
112 | "WHERE postid = #{postId,jdbcType=INTEGER} and like_by = #{uid,jdbcType=VARCHAR}",
113 | })
114 | int removeLikeRecord(int uid, int postId);
115 |
116 | @Insert({
117 | "INSERT INTO post_comment",
118 | "(postid, comment, commented_by)",
119 | "VALUES (#{postId,jdbcType=INTEGER},#{comment,jdbcType=LONGVARCHAR}, #{commentedBy,jdbcType=VARCHAR})",
120 | })
121 | int insertCommentRecord(int postId, String comment, int commentedBy);
122 |
123 | @Delete({
124 | "DELETE FROM post_comment",
125 | "WHERE comment_id = #{commentId,jdbcType=INTEGER} AND commented_by = #{uid,jdbcType=INTEGER}",
126 | })
127 | int removeCommentRecord(int commentId, int uid);
128 |
129 | @Select({
130 | "SELECT post.postid, post.text, post.posted_by, post.time_created, post.photo, post.like_count",
131 | "FROM MomentsDB.post",
132 | "ON post.postid = post_likes.postid",
133 | "GROUP BY post.postid"
134 | })
135 | @Results({
136 | @Result(column="postid", property="postid", jdbcType=JdbcType.INTEGER, id=true),
137 | @Result(column="text", property="text", jdbcType=JdbcType.VARCHAR),
138 | @Result(column="posted_by", property="postedBy", jdbcType=JdbcType.INTEGER),
139 | @Result(column="time_created", property="timeCreated", jdbcType=JdbcType.TIMESTAMP),
140 | @Result(column="photo", property="jsonPhotoUrls", jdbcType=JdbcType.LONGVARCHAR),
141 | @Result(column="like_count", property="likeCount", jdbcType=JdbcType.INTEGER)
142 | })
143 | List selectAllPosts();
144 |
145 | @Select({
146 | "SELECT like_by",
147 | "FROM post_likes",
148 | "WHERE post_id = #{postId}, jdbcType=INTEGER}"
149 | })
150 | List selectUidsThatLikedPost(int postId, int start, int limit);
151 | }
152 |
153 |
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/dao/PostSqlProvider.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.dao;
2 |
3 | import com.allen.moments.v2.model.Post;
4 | import org.apache.ibatis.jdbc.SQL;
5 |
6 | public class PostSqlProvider {
7 |
8 | public String insertSelective(Post record) {
9 | SQL sql = new SQL();
10 | sql.INSERT_INTO("post");
11 |
12 | if (record.getPostid() != null) {
13 | sql.VALUES("postid", "#{postid,jdbcType=INTEGER}");
14 | }
15 |
16 | if (record.getText() != null) {
17 | sql.VALUES("text", "#{text,jdbcType=VARCHAR}");
18 | }
19 |
20 | if (record.getPostedBy() != null) {
21 | sql.VALUES("posted_by", "#{postedBy,jdbcType=INTEGER}");
22 | }
23 |
24 | if (record.getTimeCreated() != null) {
25 | sql.VALUES("time_created", "#{timeCreated,jdbcType=TIMESTAMP}");
26 | }
27 |
28 | if (record.getLikeCount() != null) {
29 | sql.VALUES("like_count", "#{likeCount,jdbcType=INTEGER}");
30 | }
31 |
32 | if (record.getJsonPhotoUrls() != null) {
33 | sql.VALUES("photo", "#{jsonPhotoUrls,jdbcType=LONGVARCHAR}");
34 | }
35 |
36 | return sql.toString();
37 | }
38 |
39 | public String updateByPrimaryKeySelective(Post record) {
40 | SQL sql = new SQL();
41 | sql.UPDATE("post");
42 |
43 | if (record.getText() != null) {
44 | sql.SET("text = #{text,jdbcType=VARCHAR}");
45 | }
46 |
47 | if (record.getPostedBy() != null) {
48 | sql.SET("posted_by = #{postedBy,jdbcType=INTEGER}");
49 | }
50 |
51 | if (record.getTimeCreated() != null) {
52 | sql.SET("time_created = #{timeCreated,jdbcType=TIMESTAMP}");
53 | }
54 |
55 | if (record.getLikeCount() != null) {
56 | sql.SET("like_count = #{likeCount,jdbcType=INTEGER}");
57 | }
58 |
59 | if (record.getJsonPhotoUrls() != null) {
60 | sql.SET("photo = #{jsonPhotoUrls,jdbcType=LONGVARCHAR}");
61 | }
62 |
63 | sql.WHERE("postid = #{postid,jdbcType=INTEGER}");
64 |
65 | return sql.toString();
66 | }
67 | }
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/dao/UserDao.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.dao;
2 |
3 | import com.allen.moments.v2.model.User;
4 | import org.apache.ibatis.annotations.*;
5 | import org.apache.ibatis.type.JdbcType;
6 |
7 | import java.util.List;
8 |
9 | @Mapper
10 | public interface UserDao {
11 |
12 |
13 | @Delete({
14 | "delete from user",
15 | "where uid = #{uid,jdbcType=INTEGER}"
16 | })
17 | int deleteByUid(Integer uid);
18 |
19 |
20 | @Insert({
21 | "insert into user (uid, name, ",
22 | "age, sex, password, email)",
23 | "values (#{uid,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, ",
24 | "#{age,jdbcType=INTEGER}, #{sex,jdbcType=INTEGER}, #{password,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR})"
25 | })
26 | int insert(User record);
27 |
28 |
29 |
30 | @InsertProvider(type=UserSqlProvider.class, method="insertSelective")
31 | int insertSelective(User record);
32 |
33 |
34 | @Select({
35 | "select",
36 | "uid, name, age, sex, email, avatar_uri, follower_count",
37 | "from user",
38 | "where uid = #{uid,jdbcType=INTEGER}"
39 | })
40 | @Results({
41 | @Result(column="uid", property="uid", jdbcType=JdbcType.INTEGER, id=true),
42 | @Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
43 | @Result(column="age", property="age", jdbcType=JdbcType.INTEGER),
44 | @Result(column="sex", property="sex", jdbcType=JdbcType.INTEGER),
45 | @Result(column="email", property="email", jdbcType=JdbcType.VARCHAR),
46 | @Result(column="follower_count", property="followerCount", jdbcType=JdbcType.INTEGER),
47 | @Result(column="avatar_uri", property="avatarURI", jdbcType=JdbcType.VARCHAR)
48 | })
49 | User selectByUid(Integer uid);
50 |
51 | @Select({
52 | "SELECT",
53 | "uid, name, age, sex, email, follower_count, avatar_uri, password",
54 | "FROM user",
55 | "WHERE email = #{email, jdbcType=VARCHAR}"
56 | })
57 | @Results({
58 | @Result(column="uid", property="uid", jdbcType=JdbcType.INTEGER, id=true),
59 | @Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
60 | @Result(column="age", property="age", jdbcType=JdbcType.INTEGER),
61 | @Result(column="sex", property="sex", jdbcType=JdbcType.INTEGER),
62 | @Result(column="email", property="email", jdbcType=JdbcType.VARCHAR),
63 | @Result(column="follower_count", property="followerCount", jdbcType=JdbcType.INTEGER),
64 | @Result(column="avatar_uri", property="avatarURI", jdbcType=JdbcType.VARCHAR),
65 | @Result(column = "password", property = "password", jdbcType = JdbcType.VARCHAR)
66 | })
67 | User selectByEmail(String email);
68 |
69 | @Select({
70 | "select",
71 | "uid, name, age, sex. email",
72 | "from user",
73 | })
74 | @Results({
75 | @Result(column="uid", property="uid", jdbcType=JdbcType.VARCHAR, id=true),
76 | @Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
77 | @Result(column="age", property="age", jdbcType=JdbcType.INTEGER),
78 | @Result(column="sex", property="sex", jdbcType=JdbcType.INTEGER),
79 | @Result(column="email", property="email", jdbcType=JdbcType.VARCHAR)
80 | })
81 | List selectAll();
82 |
83 |
84 | @Select({
85 | "SELECT",
86 | "uid, name, age, sex, email, follower_count, avatar_uri",
87 | "FROM user",
88 | "ORDER BY follower_count DESC",
89 | "LIMIT #{start,jdbcType=INTEGER}, #{limit,jdbcType=INTEGER}"
90 | })
91 | @Results({
92 | @Result(column="uid", property="uid", jdbcType=JdbcType.INTEGER, id=true),
93 | @Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
94 | @Result(column="age", property="age", jdbcType=JdbcType.INTEGER),
95 | @Result(column="sex", property="sex", jdbcType=JdbcType.INTEGER),
96 | @Result(column="email", property="email", jdbcType=JdbcType.VARCHAR),
97 | @Result(column="follower_count", property="followerCount", jdbcType=JdbcType.INTEGER),
98 | @Result(column="avatar_uri", property="avatarURI", jdbcType=JdbcType.VARCHAR)
99 | })
100 | List selectUsersOrderByFollowerCounts(int start, int limit);
101 |
102 | @UpdateProvider(type=UserSqlProvider.class, method="updateByPrimaryKeySelective")
103 | int updateByPrimaryKeySelective(User record);
104 |
105 | @Update({
106 | "update user",
107 | "set name = #{name,jdbcType=VARCHAR},",
108 | "age = #{age,jdbcType=INTEGER},",
109 | "sex = #{sex,jdbcType=INTEGER},",
110 | "password = #{password,jdbcType=VARCHAR}",
111 | "where uid = #{uid,jdbcType=INTEGER}"
112 | })
113 | int updateByUid(User record);
114 |
115 |
116 | @Update(
117 | {
118 | "update user",
119 | "set password = #{newPassword,jdbcType=VARCHAR},",
120 | "where uid = #{uid, jdbcType=INTEGER} AND password = #{oldPassword, jdbcType=VARCHAR}",
121 | }
122 | )
123 | int updatePassword(int uid, String oldPassword, String newPassword);
124 |
125 |
126 | @Select(
127 | {
128 | "select",
129 | "max(uid)",
130 | "from user"
131 | }
132 | )
133 | int getMaxUid();
134 |
135 |
136 | @Insert({
137 | "INSERT INTO follow_relations",
138 | "(followed_id, follower_id)",
139 | "VALUES (#{followedId, jdbcType=INTEGER}, #{followerId, jdbcType=INTEGER})"
140 | })
141 | int addFollower(int followedId, int followerId);
142 |
143 | @Select({
144 | "SELECT",
145 | "follower_id",
146 | "FROM follow_relations",
147 | "WHERE followed_id = #{uid, jdbcType=INTEGER}"
148 | })
149 | List selectFollowersById(int uid);
150 |
151 | @Select({
152 | "SELECT",
153 | "followed_id",
154 | "FROM follow_relations",
155 | "WHERE follower_id = #{uid, jdbcType=INTEGER}"
156 | })
157 | List selectFollowingsById(int uid);
158 |
159 | @Delete({
160 | "DELETE FROM follow_relations",
161 | "WHERE",
162 | "followed_id = #{followedId, jdbcType=INTEGER}",
163 | "AND",
164 | "follower_id = #{followerId, jdbcType=INTEGER}"
165 | })
166 | int removeFollowingRelation(int followedId, int followerId);
167 |
168 | @Update({
169 | "UPDATE user",
170 | "SET avatar_uri = #{avatarURI, jdbcType=VARCHAR}",
171 | "WHERE uid = #{uid, jdbcType=INTEGER}"
172 | })
173 | int addAvatarURI(int uid, String avatarURI);
174 | }
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/dao/UserSqlProvider.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.dao;
2 |
3 | import com.allen.moments.v2.model.User;
4 | import org.apache.ibatis.jdbc.SQL;
5 |
6 | public class UserSqlProvider {
7 |
8 | public String insertSelective(User record) {
9 | SQL sql = new SQL();
10 | sql.INSERT_INTO("user");
11 |
12 | if (record.getUid() == 0) {
13 | sql.VALUES("uid", "#{uid,jdbcType=INTEGER}");
14 | }
15 |
16 | if (record.getName() != null) {
17 | sql.VALUES("name", "#{name,jdbcType=VARCHAR}");
18 | }
19 |
20 | if (record.getAge() != null) {
21 | sql.VALUES("age", "#{age,jdbcType=INTEGER}");
22 | }
23 |
24 | if (record.getSex() != null) {
25 | sql.VALUES("sex", "#{sex,jdbcType=INTEGER}");
26 | }
27 |
28 | if (record.getPassword() != null) {
29 | sql.VALUES("password", "#{password,jdbcType=VARCHAR}");
30 | }
31 |
32 | return sql.toString();
33 | }
34 |
35 | public String updateByPrimaryKeySelective(User record) {
36 | SQL sql = new SQL();
37 | sql.UPDATE("user");
38 |
39 | if (record.getName() != null) {
40 | sql.SET("name = #{name,jdbcType=VARCHAR}");
41 | }
42 |
43 | if (record.getAge() != null) {
44 | sql.SET("age = #{age,jdbcType=INTEGER}");
45 | }
46 |
47 | if (record.getSex() != null) {
48 | sql.SET("sex = #{sex,jdbcType=INTEGER}");
49 | }
50 |
51 | if (record.getPassword() != null) {
52 | sql.SET("password = #{password,jdbcType=VARCHAR}");
53 | }
54 |
55 | sql.WHERE("uid = #{uid,jdbcType=INTEGER}");
56 |
57 | return sql.toString();
58 | }
59 | }
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/interceptors/AuthInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.interceptors;
2 |
3 | import com.allen.moments.v2.redis.RedisUtil;
4 | import com.allen.moments.v2.utils.JsonResult;
5 | import com.allen.moments.v2.utils.annotations.PassToken;
6 | import com.allen.moments.v2.utils.annotations.RequireToken;
7 | import com.auth0.jwt.JWTVerifier;
8 | import com.auth0.jwt.algorithms.Algorithm;
9 | import com.auth0.jwt.interfaces.DecodedJWT;
10 | import com.fasterxml.jackson.databind.ObjectMapper;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.stereotype.Component;
13 | import org.springframework.web.method.HandlerMethod;
14 | import org.springframework.web.servlet.HandlerInterceptor;
15 |
16 | import javax.servlet.http.HttpServletRequest;
17 | import javax.servlet.http.HttpServletResponse;
18 | import java.lang.reflect.Method;
19 |
20 | @Component
21 | public class AuthInterceptor implements HandlerInterceptor {
22 | @Autowired
23 | RedisUtil redisUtil;
24 |
25 | @Override
26 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
27 | if (!(object instanceof HandlerMethod)) {
28 | return true;
29 | }
30 | HandlerMethod handlerMethod = (HandlerMethod) object;
31 | Method method = handlerMethod.getMethod();
32 | // allow access to methods annotated with passToken
33 | if (method.isAnnotationPresent(PassToken.class) ) {
34 | PassToken passToken = method.getAnnotation(PassToken.class);
35 | if (passToken == null) {
36 | passToken = method.getClass().getAnnotation(PassToken.class);
37 | }
38 | if (passToken.isTokenNeedless()) {
39 | return true;
40 | }
41 | }
42 | if (method.isAnnotationPresent(RequireToken.class) || method.getClass().isAnnotationPresent(RequireToken.class)) {
43 | RequireToken userLoginToken = method.getAnnotation(RequireToken.class);
44 | if (userLoginToken == null){
45 | userLoginToken = method.getClass().getAnnotation(RequireToken.class);
46 | }
47 | if (userLoginToken.isTokenNeeded()) {
48 | try { // authenticate user
49 | String authorizationHeader = request.getHeader("Authorization");
50 | if (authorizationHeader == null) {
51 | throw new RuntimeException("no token found, login is needed");
52 | }
53 | String token = authorizationHeader.substring(7);
54 | // authenticate token
55 | JWTVerifier jwtVerifier = com.auth0.jwt.JWT.require(Algorithm.HMAC256("${application.jwt.secret_key}")).build();
56 | DecodedJWT jwt = jwtVerifier.verify(token);
57 | int uid;
58 | uid = (Integer.parseInt(jwt.getAudience().get(0)));
59 | request.setAttribute("logged_uid", uid);
60 | // isLogged = redisUtil.getBit("loggedUsers", uid - 10000); // use redis as the session manager
61 | // if (!isLogged) {
62 | // throw new RuntimeException("user not found, please login again");
63 | // }
64 | }
65 | catch (Exception exception) {
66 | ObjectMapper mapper = new ObjectMapper();
67 | System.err.println(exception.getMessage());
68 | JsonResult> jsonResult = JsonResult.failure(10000, "user not logged or login expired");// customised pojo for error json message
69 | response.setContentType("application/json");
70 | response.setCharacterEncoding("utf-8");
71 | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
72 | response.getWriter().write(mapper.writeValueAsString(jsonResult));
73 | return false;
74 | }
75 |
76 | }
77 | }
78 | return true;
79 | }
80 |
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/interceptors/InterceptorConfig.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.interceptors;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.web.servlet.HandlerInterceptor;
6 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
8 |
9 | @Configuration
10 | public class InterceptorConfig implements WebMvcConfigurer {
11 | @Override
12 | public void addInterceptors(InterceptorRegistry registry) {
13 | registry.addInterceptor(authenticationInterceptor())
14 | .addPathPatterns("/**"); // intercept all requests and use authentication interceptor to decide whether login is needed
15 | }
16 | @Bean
17 | public HandlerInterceptor authenticationInterceptor() {
18 | return new AuthInterceptor();
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/model/Comment.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.model;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.Arrays;
6 | import java.util.List;
7 |
8 | public class Comment {
9 |
10 | private Integer commentId;
11 |
12 | private Integer postid;
13 |
14 | private String comment;
15 |
16 | private Integer commentedby;
17 |
18 | public Integer getCommentId() {
19 | return commentId;
20 | }
21 |
22 | public void setCommentId(Integer commentId) {
23 | this.commentId = commentId;
24 | }
25 |
26 | public Integer getPostid() {
27 | return postid;
28 | }
29 |
30 | public void setPostid(Integer postid) {
31 | this.postid = postid;
32 | }
33 |
34 | public String getComment() {
35 | return comment;
36 | }
37 |
38 | public void setComment(String comment) {
39 | this.comment = comment == null ? null : comment.trim();
40 | }
41 |
42 | public Integer getCommentedby() {
43 | return commentedby;
44 | }
45 |
46 | public void setCommentedby(Integer commentedby) {
47 | this.commentedby = commentedby;
48 | }
49 |
50 | @Override
51 | public boolean equals(Object that) {
52 | if (this == that) {
53 | return true;
54 | }
55 | if (that == null) {
56 | return false;
57 | }
58 | if (getClass() != that.getClass()) {
59 | return false;
60 | }
61 | Comment other = (Comment) that;
62 | return (this.getCommentId() == null ? other.getCommentId() == null : this.getCommentId().equals(other.getCommentId()))
63 | && (this.getPostid() == null ? other.getPostid() == null : this.getPostid().equals(other.getPostid()))
64 | && (this.getComment() == null ? other.getComment() == null : this.getComment().equals(other.getComment()))
65 | && (this.getCommentedby() == null ? other.getCommentedby() == null : this.getCommentedby().equals(other.getCommentedby()));
66 | }
67 |
68 | @Override
69 | public int hashCode() {
70 | final int prime = 31;
71 | int result = 1;
72 | result = prime * result + ((getCommentId() == null) ? 0 : getCommentId().hashCode());
73 | result = prime * result + ((getPostid() == null) ? 0 : getPostid().hashCode());
74 | result = prime * result + ((getComment() == null) ? 0 : getComment().hashCode());
75 | result = prime * result + ((getCommentedby() == null) ? 0 : getCommentedby().hashCode());
76 | return result;
77 | }
78 | }
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/model/DML.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.model;
2 |
3 | public enum DML {
4 | UPDATE("update"),
5 | INSERT("insertion"),
6 | DELETE("deletion");
7 |
8 | public final String description;
9 |
10 | DML (String description) {
11 | this.description = description;
12 | }
13 |
14 | @Override
15 | public String toString() {
16 | return "DML{" +
17 | "description='" + description + '\'' +
18 | '}';
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/model/ErrorType.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.model;
2 |
3 | import java.io.Serializable;
4 |
5 | public enum ErrorType implements Serializable {
6 |
7 | // user related
8 | UNKNOWN_ERROR(100000, "unknown error"),
9 | USER_ALREADY_REGISTERED(100001, "user already registered"),
10 | USER_ALREADY_FOLLOWED(100002, "user already followed"),
11 | PASSWORD_ACCOUNT_MISMATCH(100003, "Password incorrect"),
12 | NO_FOLLOWING_RELATION(200001, "no following relationship exists"),
13 | USER_UNIDENTIFIED(200002, "cannot find user"),
14 |
15 | DIRTY_DATA(900000, "dirty data exists"),
16 | DML_ERR(900001, "DML error");
17 |
18 | public final int errNo;
19 | public final String message;
20 |
21 | ErrorType(int errNo, String message) {
22 | this.errNo = errNo;
23 | this.message = message;
24 | }
25 |
26 | @Override
27 | public String toString() {
28 | return "Error{" +
29 | "code=" + errNo +
30 | ", message='" + message + '\'' +
31 | '}';
32 | }
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/model/Like.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.model;
2 |
3 | public class Like {
4 | private Integer postid;
5 |
6 | private Integer likeby;
7 |
8 | public Integer getPostid() {
9 | return postid;
10 | }
11 |
12 | public void setPostid(Integer postid) {
13 | this.postid = postid;
14 | }
15 |
16 | public Integer getLikeby() {
17 | return likeby;
18 | }
19 |
20 | public void setLikeby(Integer likeby) {
21 | this.likeby = likeby;
22 | }
23 |
24 | @Override
25 | public boolean equals(Object that) {
26 | if (this == that) {
27 | return true;
28 | }
29 | if (that == null) {
30 | return false;
31 | }
32 | if (getClass() != that.getClass()) {
33 | return false;
34 | }
35 | Like other = (Like) that;
36 | return (this.getPostid() == null ? other.getPostid() == null : this.getPostid().equals(other.getPostid()))
37 | && (this.getLikeby() == null ? other.getLikeby() == null : this.getLikeby().equals(other.getLikeby()));
38 | }
39 |
40 | @Override
41 | public int hashCode() {
42 | final int prime = 31;
43 | int result = 1;
44 | result = prime * result + ((getPostid() == null) ? 0 : getPostid().hashCode());
45 | result = prime * result + ((getLikeby() == null) ? 0 : getLikeby().hashCode());
46 | return result;
47 | }
48 | }
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/model/Photo.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.model;
2 |
3 | public class Photo {
4 | private Integer postid;
5 |
6 | private String url;
7 |
8 | public Integer getPostId() {
9 | return postid;
10 | }
11 |
12 | public void setPostId(Integer postid) {
13 | this.postid = postid;
14 | }
15 |
16 | public String getUrl() {
17 | return url;
18 | }
19 |
20 | public void setUrl(String url) {
21 | this.url = url == null ? null : url.trim();
22 | }
23 |
24 | @Override
25 | public boolean equals(Object that) {
26 | if (this == that) {
27 | return true;
28 | }
29 | if (that == null) {
30 | return false;
31 | }
32 | if (getClass() != that.getClass()) {
33 | return false;
34 | }
35 | Photo other = (Photo) that;
36 | return (this.getPostId() == null ? other.getPostId() == null : this.getPostId().equals(other.getPostId()))
37 | && (this.getUrl() == null ? other.getUrl() == null : this.getUrl().equals(other.getUrl()));
38 | }
39 |
40 | @Override
41 | public int hashCode() {
42 | final int prime = 31;
43 | int result = 1;
44 | result = prime * result + ((getPostId() == null) ? 0 : getPostId().hashCode());
45 | result = prime * result + ((getUrl() == null) ? 0 : getUrl().hashCode());
46 | return result;
47 | }
48 | }
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/model/Post.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.model;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 |
5 | import java.util.Date;
6 | import java.util.List;
7 |
8 | public class Post {
9 | private Integer postid;
10 |
11 | private String text;
12 |
13 | private Integer postedBy;
14 |
15 | private Date timeCreated;
16 |
17 | private Integer likeCount;
18 |
19 | private List photoUrls;
20 |
21 | private String jsonPhotoUrls;
22 |
23 | public Post() {}
24 |
25 | public Post(Integer postid, String text, Integer postedBy, List photoUrls) {
26 | this.postid = postid;
27 | this.text = text;
28 | this.postedBy = postedBy;
29 | this.photoUrls = photoUrls;
30 | this.jsonPhotoUrls = JSONObject.toJSONString(this.photoUrls);
31 | }
32 |
33 | public Post(Integer postid, String text, Integer postedBy) {
34 | this.postid = postid;
35 | this.text = text;
36 | this.postedBy = postedBy;
37 | }
38 |
39 | public Integer getPostid() {
40 | return postid;
41 | }
42 |
43 | public void setPostid(Integer postid) {
44 | this.postid = postid;
45 | }
46 |
47 | public String getText() {
48 | return text;
49 | }
50 |
51 | public void setText(String text) {
52 | this.text = text == null ? null : text.trim();
53 | }
54 |
55 | public Integer getPostedBy() {
56 | return postedBy;
57 | }
58 |
59 | public void setPostedBy(Integer postedBy) {
60 | this.postedBy = postedBy;
61 | }
62 |
63 | public Date getTimeCreated() {
64 | return timeCreated;
65 | }
66 |
67 | public void setTimeCreated(Date timeCreated) {
68 | this.timeCreated = timeCreated;
69 | }
70 |
71 | public Integer getLikeCount() {
72 | return likeCount;
73 | }
74 |
75 | public void setLikeCount(Integer likeCount) {
76 | this.likeCount = likeCount;
77 | }
78 |
79 | public List getPhotoUrls() {
80 | return photoUrls;
81 | }
82 |
83 | public void setPhotoUrls(List photoUrls) {
84 | this.photoUrls = photoUrls;
85 | }
86 |
87 | public String getJsonPhotoUrls() {
88 | return jsonPhotoUrls;
89 | }
90 |
91 | public void setJsonPhotoUrls(String jsonPhotoUrls) {
92 | this.jsonPhotoUrls = null;
93 | this.photoUrls = JSONObject.parseArray(jsonPhotoUrls, String.class);
94 | }
95 |
96 | @Override
97 | public boolean equals(Object that) {
98 | if (this == that) {
99 | return true;
100 | }
101 | if (that == null) {
102 | return false;
103 | }
104 | if (getClass() != that.getClass()) {
105 | return false;
106 | }
107 | Post other = (Post) that;
108 | return (this.getPostid() == null ? other.getPostid() == null : this.getPostid().equals(other.getPostid()))
109 | && (this.getText() == null ? other.getText() == null : this.getText().equals(other.getText()))
110 | && (this.getPostedBy() == null ? other.getPostedBy() == null : this.getPostedBy().equals(other.getPostedBy()))
111 | && (this.getTimeCreated() == null ? other.getTimeCreated() == null : this.getTimeCreated().equals(other.getTimeCreated()))
112 | && (this.getLikeCount() == null ? other.getLikeCount() == null : this.getLikeCount().equals(other.getLikeCount()))
113 | && (this.getPhotoUrls() == null ? other.getPhotoUrls() == null : this.getPhotoUrls().equals(other.getPhotoUrls()));
114 | }
115 |
116 | @Override
117 | public int hashCode() {
118 | final int prime = 31;
119 | int result = 1;
120 | result = prime * result + ((getPostid() == null) ? 0 : getPostid().hashCode());
121 | result = prime * result + ((getText() == null) ? 0 : getText().hashCode());
122 | result = prime * result + ((getPostedBy() == null) ? 0 : getPostedBy().hashCode());
123 | result = prime * result + ((getTimeCreated() == null) ? 0 : getTimeCreated().hashCode());
124 | result = prime * result + ((getLikeCount() == null) ? 0 : getLikeCount().hashCode());
125 | result = prime * result + ((getPhotoUrls() == null) ? 0 : getPhotoUrls().hashCode());
126 | return result;
127 | }
128 | }
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/model/User.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.model;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class User {
7 | private int uid;
8 | private String name;
9 | private Integer age;
10 | private transient String password;
11 | private String email;
12 | private Integer sex;
13 | private List followers;
14 | private List followings;
15 | private Integer followerCount;
16 | private String avatarURI;
17 |
18 | public User(String name, String email, Integer uid, Integer age, Integer sex, String password) {
19 | this.name = name;
20 | this.age = age;
21 | this.password = password;
22 | this.uid = uid;
23 | this.sex = sex;
24 | this.email = email;
25 | }
26 |
27 | public User(Integer uid, String name, Integer age, Integer sex, String email) {
28 | this.name = name;
29 | this.age = age;
30 | this.uid = uid;
31 | this.sex = sex;
32 | this.email = email;
33 | }
34 |
35 | public User(Integer uid, String name, Integer age, Integer sex, String email, int followerCount) {
36 | this.name = name;
37 | this.age = age;
38 | this.uid = uid;
39 | this.sex = sex;
40 | this.email = email;
41 | this.followerCount = followerCount;
42 | }
43 |
44 | public User(Integer uid, String name, Integer age, Integer sex, String email, int followerCount, String avatarURI) {
45 | this.name = name;
46 | this.age = age;
47 | this.uid = uid;
48 | this.sex = sex;
49 | this.email = email;
50 | this.followerCount = followerCount;
51 | this.avatarURI = avatarURI;
52 | }
53 |
54 | public User(Integer uid, String name, Integer age, Integer sex, String email, int followerCount, String avatarURI, String password) {
55 | this.name = name;
56 | this.age = age;
57 | this.uid = uid;
58 | this.sex = sex;
59 | this.email = email;
60 | this.followerCount = followerCount;
61 | this.avatarURI = avatarURI;
62 | this.password = password;
63 | }
64 |
65 | public int getUid() {
66 | return uid;
67 | }
68 |
69 | public void setUid(int uid) {
70 | this.uid = uid;
71 | }
72 |
73 | public String getName() {
74 | return name;
75 | }
76 |
77 | public void setName(String name) {
78 | this.name = name == null ? null : name.trim();
79 | }
80 |
81 | public Integer getAge() {
82 | return age;
83 | }
84 |
85 | public void setAge(Integer age) {
86 | this.age = age;
87 | }
88 |
89 | public Integer getSex() {
90 | return sex;
91 | }
92 |
93 | public void setSex(Integer sex) {
94 | this.sex = sex;
95 | }
96 |
97 | public String getEmail() {
98 | return email;
99 | }
100 |
101 | public void setEmail(String email) {
102 | this.email = email;
103 | }
104 |
105 | public List getFollowers() {
106 | return followers;
107 | }
108 |
109 |
110 | public List getFollowings() {
111 | return followings;
112 | }
113 |
114 | public void addFollowing(Integer uidToFollow) {
115 | this.followings.add(uidToFollow);
116 | }
117 |
118 | public Integer getFollowerCount() {
119 | return followerCount;
120 | }
121 |
122 | public void setFollowerCount(Integer followerCount) {
123 | this.followerCount = followerCount;
124 | }
125 |
126 | public String getAvatarURI() {
127 | return this.avatarURI;
128 | }
129 |
130 | public void setAvatarURI(String avatarURI) {
131 | this.avatarURI = avatarURI;
132 | }
133 |
134 | @Override
135 | public boolean equals(Object that) {
136 | if (this == that) {
137 | return true;
138 | }
139 | if (that == null) {
140 | return false;
141 | }
142 | if (getClass() != that.getClass()) {
143 | return false;
144 | }
145 | User other = (User) that;
146 | return (this.getUid() == 0 ? other.getUid() == 0 : this.getUid() == other.getUid())
147 | && (this.getName() == null ? other.getName() == null : this.getName().equals(other.getName()))
148 | && (this.getAge() == null ? other.getAge() == null : this.getAge().equals(other.getAge()))
149 | && (this.getSex() == null ? other.getSex() == null : this.getSex().equals(other.getSex()));
150 | }
151 |
152 | @Override
153 | public int hashCode() {
154 | final int prime = 31;
155 | int result = 1;
156 | result = prime * result + ((getUid() == 0) ? 0 : getUid());
157 | result = prime * result + ((getName() == null) ? 0 : getName().hashCode());
158 | result = prime * result + ((getAge() == null) ? 0 : getAge().hashCode());
159 | result = prime * result + ((getSex() == null) ? 0 : getSex().hashCode());
160 | return result;
161 | }
162 |
163 | public String getPassword() {
164 | return this.password;
165 | }
166 | public void setPassword(String password) {
167 | this.password = password;
168 | }
169 |
170 | }
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/redis/RedisConfig.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.redis;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAutoDetect;
4 | import com.fasterxml.jackson.annotation.PropertyAccessor;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.beans.factory.annotation.Qualifier;
9 | import org.springframework.boot.autoconfigure.AutoConfigureAfter;
10 | import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
11 | import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
12 | import org.springframework.context.annotation.Bean;
13 | import org.springframework.context.annotation.Configuration;
14 | import org.springframework.data.redis.connection.RedisClusterConfiguration;
15 | import org.springframework.data.redis.connection.RedisNode;
16 | import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
17 | import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
18 | import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
19 | import org.springframework.data.redis.core.RedisTemplate;
20 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
21 | import org.springframework.data.redis.serializer.StringRedisSerializer;
22 |
23 | import java.util.ArrayList;
24 |
25 |
26 | @Configuration
27 | @AutoConfigureAfter(RedisAutoConfiguration.class)
28 | public class RedisConfig {
29 | @Autowired
30 | RedisProperties redisProperties;
31 |
32 | @Bean
33 | public GenericObjectPoolConfig poolConfig() {
34 | GenericObjectPoolConfig config = new GenericObjectPoolConfig();
35 | config.setMinIdle(redisProperties.getLettuce().getPool().getMinIdle());
36 | config.setMaxIdle(redisProperties.getLettuce().getPool().getMaxIdle());
37 | config.setMaxTotal(redisProperties.getLettuce().getPool().getMaxActive());
38 | config.setMaxWaitMillis(redisProperties.getLettuce().getPool().getMaxWait().toMillis());
39 | return config;
40 | }
41 |
42 | /**
43 | * @Description: add sentinel config
44 | */
45 | @Bean
46 | public RedisClusterConfiguration configuration() {
47 | RedisClusterConfiguration redisConfig = new RedisClusterConfiguration();
48 | // redisConfig.setPassword(RedisPassword.of(redisConfigThree.getPassword()));
49 | if(redisProperties.getSentinel().getNodes()!=null) {
50 | ArrayList nodes =new ArrayList();
51 | for(String sen : redisProperties.getCluster().getNodes()) {
52 | String[] hostWithPort = sen.split(":");
53 | nodes.add(new RedisNode(hostWithPort[0], Integer.parseInt(hostWithPort[1])));
54 | }
55 | redisConfig.setClusterNodes(nodes);
56 | }
57 | return redisConfig;
58 | }
59 |
60 |
61 | @Bean("RedisConnectionFactory")
62 | public LettuceConnectionFactory RedisConnectionFactory(@Qualifier("poolConfig") GenericObjectPoolConfig config,
63 | @Qualifier("configuration") RedisClusterConfiguration redisConfig) {//注意传入的对象名和类型RedisSentinelConfiguration
64 | LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
65 | return new LettuceConnectionFactory(redisConfig, clientConfiguration);
66 | }
67 |
68 |
69 | @Bean(name = "redisTemplate")
70 | public RedisTemplate redisTemplate(@Qualifier("RedisConnectionFactory") LettuceConnectionFactory factory) {
71 | RedisTemplate template = new RedisTemplate<>();
72 | template.setConnectionFactory(factory);
73 | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
74 | ObjectMapper om = new ObjectMapper();
75 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
76 | om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
77 | jackson2JsonRedisSerializer.setObjectMapper(om);
78 | StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
79 | template.setKeySerializer(stringRedisSerializer);
80 | template.setHashKeySerializer(stringRedisSerializer);
81 | template.setValueSerializer(jackson2JsonRedisSerializer);
82 | template.setHashValueSerializer(jackson2JsonRedisSerializer);
83 | template.afterPropertiesSet();
84 | return template;
85 | }
86 | }
--------------------------------------------------------------------------------
/src/main/java/com/allen/moments/v2/redis/RedisUtil.java:
--------------------------------------------------------------------------------
1 | package com.allen.moments.v2.redis;
2 | import org.springframework.beans.factory.annotation.Autowired;
3 | import org.springframework.data.redis.core.RedisTemplate;
4 | import org.springframework.data.redis.core.ZSetOperations;
5 | import org.springframework.stereotype.Component;
6 | import org.springframework.util.CollectionUtils;
7 |
8 | import java.util.*;
9 | import java.util.concurrent.TimeUnit;
10 |
11 | @Component
12 | public final class RedisUtil {
13 |
14 | @Autowired
15 | private RedisTemplate redisTemplate;
16 |
17 | // =============================Common============================
18 |
19 | /**
20 | * set the expiration time of a key
21 | *
22 | * @param key key
23 | * @param time time in second
24 | */
25 | public void expire(String key, long time) {
26 | try {
27 | if (time > 0) {
28 | redisTemplate.expire(key, time, TimeUnit.SECONDS);
29 | }
30 | } catch (Exception e) {
31 | e.printStackTrace();
32 | }
33 | }
34 |
35 | /**
36 | * get expiration time of a key
37 | *
38 | * @param key not null
39 | * @return expiration time in seconds
40 | */
41 | public long getExpire(String key) {
42 | return redisTemplate.getExpire(key, TimeUnit.SECONDS);
43 | }
44 |
45 | /**
46 | * check if a key exists
47 | *
48 | * @return true if exists, false otherwise;
49 | */
50 | public Boolean hasKey(String key) {
51 | try {
52 | return redisTemplate.hasKey(key);
53 | } catch (Exception e) {
54 | e.printStackTrace();
55 | return false;
56 | }
57 | }
58 |
59 | /**
60 | * delete key
61 | *
62 | * @param key could be one or multiple keys
63 | * whether operation is success or not
64 | */
65 | @SuppressWarnings("unchecked")
66 | public void deleteKey(String... key) {
67 | if (key != null && key.length > 0) {
68 | if (key.length == 1) {
69 | redisTemplate.delete(key[0]);
70 | } else {
71 | redisTemplate.delete((Collection) CollectionUtils.arrayToList(key));
72 | }
73 | }
74 | }
75 |
76 | // ============================String=============================
77 |
78 | /**
79 | * get value
80 | *
81 | * @return value
82 | */
83 | public Object get(String key) {
84 | return key == null ? null : redisTemplate.opsForValue().get(key);
85 | }
86 |
87 |
88 | public boolean set(String key, Object value) {
89 | try {
90 | redisTemplate.opsForValue().set(key, value);
91 | return true;
92 | } catch (Exception e) {
93 | e.printStackTrace();
94 | return false;
95 | }
96 | }
97 |
98 | /**
99 | * set key and value with expiration time
100 | *
101 | * @param time expiration time in seconds, -1 for no expiration
102 | * @return true if success false otherwise
103 | */
104 | public boolean set(String key, Object value, long time) {
105 | try {
106 | if (time > 0) {
107 | redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
108 | } else {
109 | set(key, value);
110 | }
111 | return true;
112 | } catch (Exception e) {
113 | e.printStackTrace();
114 | return false;
115 | }
116 | }
117 |
118 | /**
119 | * increase a key's value by certain number
120 | *
121 | * @param delta the number to add to the key's value
122 | */
123 | public Long incr(String key, long delta) {
124 | if (delta < 0) {
125 | throw new RuntimeException("delta must be greater or equal to than zero");
126 | }
127 | return redisTemplate.opsForValue().increment(key, delta);
128 | }
129 |
130 | /**
131 | * decrease a key's value by certain number
132 | *
133 | * @param delta the number to minus from the key's value
134 | */
135 | public long decr(String key, long delta) {
136 | if (delta < 0) {
137 | throw new RuntimeException("delta must be greater or equal to than zero");
138 | }
139 | return redisTemplate.opsForValue().increment(key, -delta);
140 | }
141 |
142 | // ================================Map=================================
143 |
144 | /**
145 | * HashGet
146 | *
147 | * @param key not null
148 | * @param item not null
149 | */
150 | public Object hashGet(String key, String item) {
151 | return redisTemplate.opsForHash().get(key, item);
152 | }
153 |
154 | public Map