lab session | Names | student IDs |
---|---|---|
3 | 程嘉朗 | 12111622 |
3 | 伍福临 | 12110411 |
-
MainController.java
-
query
@GetMapping("/query") @ResponseBody public List<Users> query()
- HTTP request type: get
- Function and return value: return a list of all users, including all the information that needs to be rendered
-
findCurrentUser
@GetMapping("/current_user") @ResponseBody public String findCurrentUser(HttpServletRequest request)
- HTTP request type: get
- Function and return value: return the current user name
-
findCurrentUserId
@GetMapping("/current_userId") @ResponseBody public long findCurrentUserId(HttpServletRequest request)
- HTTP request type: get
- Function and return value: return the current user ID
-
login
@GetMapping("/login") @ResponseBody public String login(HttpServletRequest request, HttpServletResponse response)
- HTTP request type: get
- Function and return value: return whether the user has login
-
login
@PostMapping("/login") @ResponseBody public String login(@RequestBody Users user, Model model, HttpServletRequest request, HttpServletResponse response)
-
HTTP request type: post
-
Function and return value: return whether the user input valid username and password
-
-
signup
@GetMapping("/signup") @ResponseBody public String signup(HttpServletRequest request, HttpServletResponse response)
- HTTP request type: get
- Function and return value: return whether the user need to login or signup
-
signup
@PostMapping("/signup") @ResponseBody public Map<String, String> register(@RequestBody Users user, HttpServletResponse response)
-
HTTP request type: post
-
Function and return value: return whether username, password, phone meet the reqirement
-
-
logout
@DeleteMapping("/logout") @ResponseBody public String logout(HttpServletRequest request, HttpServletResponse response)
-
HTTP request type: delete
-
Function and return value: delete the cookies and return successfuly logout
-
-
-
usercontroller
-
findPostInPage
,findShareInPage
,findLikeInPage
,findFavoriteInPage
@GetMapping("/homepage/post") public List<Posts> findPostInPage(@RequestParam("lastPostId") Long lastPostId, @RequestParam("limit") int limit, HttpServletRequest request, HttpServletResponse response) @GetMapping("/homepage/share") public List<Posts> findShareInPage(@RequestParam("lastPostId") Long lastPostId, HttpServletRequest request, @RequestParam("limit") int limit, HttpServletResponse response) @GetMapping("/homepage/like") public List<Posts> findLikeInPage(@RequestParam("lastPostId") Long lastPostId, HttpServletRequest request, @RequestParam("limit") int limit, HttpServletResponse response) @GetMapping("/homepage/favorite") public List<Posts> findFavoriteInPage(@RequestParam("lastPostId") Long lastPostId, HttpServletRequest request, @RequestParam("limit") int limit, HttpServletResponse response)
-
HTTP request type: get
-
Request Parameter:
lastPostId
:The ID of the last postlimit
: Limit how many the latest posts you can get -
Function and return value: return the latest limit posts
-
-
findHotPostInPage
@GetMapping("/homepage/hotpost") public List<Posts> findHotPostInPage(@RequestParam("lastPostId") Long lastPostId, @RequestParam("limit") int limit, HttpServletRequest request, HttpServletResponse response)
-
HTTP request type: get
-
Request Parameter:
lastPostId
:The ID of the hottest postlimit
: Limit how many the hottest posts you can get -
Function and return value: return the hottest limit posts
-
-
searchPost
@PostMapping("/homepage/search") public List<Posts> searchPost(@RequestBody ArrayList<Filter> filters, HttpServletRequest request)
-
HTTP request type: post
-
Request Body: a list of filters(self-define objects), indicating restrictions for searching the posts
-
Function and return value: return the posts that meet the restrictions
-
-
findYourPostInPage
,findMyPost
@GetMapping("/homepage/yourPost") public List<Posts> findYourPostInPage(@RequestParam("lastPostId") Long lastPostId, HttpServletRequest request, @RequestParam("limit") int limit, HttpServletResponse response) @GetMapping("/user/homepage/post") public List<Posts> findMyPost(@RequestParam long senderId, HttpServletRequest request, HttpServletResponse response)
-
HTTP request type: get
-
Response data format: json
-
Request Parameter:
lastPostId
:The ID of the your last postlimit
:Limit how many your latest posts you can get -
Function and return value: return your latest limit posts
-
-
findMyReplyPost
@GetMapping("/user/homepage/yourReplyPost") public List<Posts> findMyReplyPost(HttpServletRequest request, HttpServletResponse response)
-
HTTP request type: get
-
Response data format: json
-
Function and return value: return the your Reply posts
-
-
sendPosts
@PostMapping("/user/homepage/post") public int sendPosts(@RequestBody Posts posts, HttpServletRequest request, HttpServletResponse response)
-
HTTP request type: post
-
Request Body:
-
Function and return value: Post articles and return 1 if succeeds
-
-
uploadPic
@PostMapping("/Files/users/{userId}") public void uploadPic(HttpServletRequest request, HttpServletResponse response, @RequestBody MultipartFile file, @PathVariable long userId)
-
HTTP request type: post
-
Request Body: a file(which can be video or picture)
-
Path Variable: a subdirectory indicating that the files belong to the specified user
-
Function: Upload picture when post
-
-
findMyReplies
@GetMapping("/user/homepage/replies") public List<Replies> findMyReplies(HttpServletRequest request, HttpServletResponse response)
- HTTP request type: get
- Function and return value: return all my replies
-
findReplyByPost
@GetMapping("/user/homepage/post/replies") public List<Replies> findReplyByPost(@RequestParam("id") Long postId, HttpServletRequest request, HttpServletResponse response)
-
HTTP request type: get
-
Request Parameter:
id
: The corresponding post id -
Function and return value: return the reply of the corresponding post id
-
-
sendReplies
@PostMapping("/user/homepage/replies") public int sendReplies(@RequestBody Replies replies, HttpServletRequest request, HttpServletResponse response)
-
HTTP request type: post
-
Request Body: All information need to store in replies
-
Function: Send replies and return 1 if succeeds.
-
-
starReply
@PostMapping("/user/homepage/replies/star") public int starReply(@RequestParam("replyId") long replyId, HttpServletRequest request, HttpServletResponse response)
-
HTTP request type: post
-
Request Parameter: the id of the corresponding reply
-
Function: Star the corresponding reply and return 1 if succeeds.
-
-
likePost
@PostMapping("/user/like") public String likePost(@RequestBody LikePostWrapper lpw, HttpServletRequest request, HttpServletResponse response)
-
HTTP request type: post
-
Request Body:
-
Function: Like post
-
-
unLike
@DeleteMapping("/user/like") public int unLike(@RequestParam("postId") long postId, HttpServletRequest request, HttpServletResponse response)
- HTTP request type: delete
- Request Param: the id of the corresponding liked post
- Function and return value: un like the corresponding post, return 1 if succeed.
-
checkLikes
@GetMapping("/user/like") public List<Posts> checkLikes(HttpServletRequest request, HttpServletResponse response)
- HTTP request type: get
- Function: Get the liked posts
-
favorPost
@PostMapping("/user/favor") public String favorPost(@RequestBody FavorPostWrapper fpw, HttpServletRequest request, HttpServletResponse response)
-
HTTP request type: post
-
Request Body: the postId which is favored
-
Function: Favorite post
-
-
unFavorite
@DeleteMapping("/user/favorite") public int unFavorite(@RequestParam("postId") long postId, HttpServletRequest request, HttpServletResponse response)
- HTTP request type: delete
- Request Param: the id of the corresponding favorited post
- Function and return value: un favorite the corresponding post, return 1 if succeed.
-
checkFavors
@GetMapping("/user/favor") public List<Posts> checkFavors(HttpServletRequest request, HttpServletResponse response)
- HTTP request type: get
- Function and return value: return the favorited posts
-
sharePost
@PostMapping("/user/share") public String sharePost(@RequestBody SharePostWrapper spw, HttpServletRequest request, HttpServletResponse response)
- HTTP request type: post
- Request Body: the postId which is shared
- Function and return value: Share post, return success
-
unSharePost
@DeleteMapping("/user/share") public String unSharePost(@RequestParam("postId") long originalPostId, HttpServletRequest request, HttpServletResponse response)
- HTTP request type: delete
- Request Param: the id of the corresponding post
- Function and return value: Revoke sharing the corresponding post and return success
-
checkShares
@GetMapping("/user/share") public List<Posts> checkShares(HttpServletRequest request, HttpServletResponse response)
- HTTP request type: get
- Function and return value: return your shared posts
-
findShareIds
@GetMapping("user/share/ids") public List<Long> findShareIds(HttpServletRequest request, HttpServletResponse response)
- HTTP request type: get
- Function and return value: return the id of your shared posts
-
follow
@PostMapping("/user/follow") public int follow(@RequestBody FollowUserWrapper fuw, HttpServletRequest request, HttpServletResponse response)
- HTTP request type: post
- Request Body: the followed userid
- Function and return value: Follow users and return 1 if succeed
-
unfollow
@DeleteMapping("/user/follow") public int unfollow(@RequestParam("followigid") long followigid, HttpServletRequest request, HttpServletResponse response)
- HTTP request type: delete
- Request Param: the corresponding id of the followed users
- Function and return value: un follow the corresponding users, return 1 if succeed
-
findFollow
@GetMapping("/user/follow") public List<Users> findFollow(HttpServletRequest request, HttpServletResponse response, @RequestParam("offset") long offset, @RequestParam("limit") long limit)
-
HTTP request type: get
-
Request Param:
offest
: how many users has been gotlimit
: how many users are needed in this request -
Function and return value: return your followed users
-
-
findFollowIds
@GetMapping("user/follow/ids") public List<Long> findFollowIds(HttpServletRequest request, HttpServletResponse response)
- HTTP request type: get
- Function and return value: return the id of your followed users
-
shield
@PostMapping("/user/shield") public int shield(@RequestBody ShieldUserWrapper fuw, HttpServletRequest request, HttpServletResponse response)
- HTTP request type: post
- Request Body: the id you need to shield
- Function and return value: Shield users, return 1 if succeed
-
unshield
@DeleteMapping("/user/shield") public int unshield(@RequestParam("shieldid") long shieldid, HttpServletRequest request, HttpServletResponse response)
- HTTP request type: delete
- Request Param: the corresponding id of the shielded users
- Function and return value: un shield the corresponding users, return 1 if succeed
-
-
Complete the project using
opengauss
database (task 1)Install opengauss:
-
Install a linux os:
centos 7
-
Install
docker
incentos 7
-
Use
docker
to pullopengauss
-
Use
docker
to runopengauss
systemctl start docker docker start opengauss
-
connect to the
opengauss
indatagrip
-
-
Enhance the usability of the APIs (task 2)
-
Speak anonymously
-
We allow users post or comment anonymously.
-
When users post or comment or reply comment, they can choose public or anonymous by a switch
-
Once it is anonymous, others users can't see who send the post or the comment.
How to achieve anonymity?
-
Actually, in the database, the true information of poster or replier are still be registered. But we record whether it is anonymous.
post anonymously
@Insert("insert into posts(title, content, postingtime, authorid, city, country, senderid, anonymous, originpostid, filePath, issenderanonymous) " +"values (#{title}, #{content}, #{postingTime}, #{authorId}, #{city}, #{country}, #{senderId}, #{anonymous}, #{postId}, #{filepath}, #{issenderanonymous}) returning postid")
anonymous
is used to record the author of the post whether is anonymous or notissenderanonymous
is used to record the sender of the post whether is anonymous or notwhen we need to show the post, we do Query from database, and then judge the two attributes to render the front-end interface.
<el-tag type="success" style="margin-right: 10px">{{!this.post.anonymous ? post.senderName : "anonymous"}}</el-tag>
<el-tag type="success" style="margin-right: 10px">{{!this.post.issenderanonymous ? post.authorName
comment anonymously
@Insert("insert into replies(toreplyid, topostid, content, stars, authorid, anonymous, orginalanonymous) " + "VALUES (#{toreplyid}, #{topostid}, #{content}, #{stars}, #{authorid}, #{anonymous}, #{orginalanonymous})")
anonymous
is used to record the author of the reply whether is anonymous or notorginalanonymous
is used to to record the author of the original reply the author replied whether is anonymous or notwhen we need to show the reply, we do Query from database, and then judge the two attributes to render the front-end interface.
<el-tag type="success" style="margin-right: 10px">{{item.anonymous ? "anonymous" : item.authorName}}</el-tag>
<el-tag type="success" style="margin-right: 10px" v-if="item.toUserName">{{item.orginalanonymous ? "anonymous" : item.toUserName }}</el-tag>
-
-
picture and video upload
-
use
el-upload
component inelement-ui
-
bind a reference
upload
to the component<el-upload ref="upload"></el-upload>
-
specific the location(the static resourse directory of the springboot)
<el-upload ref="upload" :action= '`http://localhost:9090/Files/users/${this.userId}`'> </el-upload>
-
use function
submit()
to upload the sourcethis.$refs.upload.submit();
-
store the filepath in the database
-
when get the posts from the back-end, the from-end also get the file path, hence it can access the file and show it
-
-
shield
-
we allow the users to shield other users
-
When user want to shield other users, search it in all users and then click the switch the state of shield
-
There is a table to record other users the user have shield
@Insert("insert into shieldby(userID, shieldID) values(#{userid}, #{shieldigid});")
-
when we need to show the post, we do Query from database, filter authors and senders who are not shield by current users.
@Select("select p.*, u.username authorname, v.username sendername \n" + "from posts p join users u on p.authorid = u.userid join users v on p.senderid = v.userid \n" + "where postid <= #{lastPostId} and postid > #{lastPostId} - #{limit} \n" + "and u.userID not in (select shieldID from shieldby where userID = #{userid})\n" + "and v.userID not in (select shieldID from shieldby where userID = #{userid})\n" + "order by p.postid desc;")
Here we only show the code of homepage where we show the posts. Actually, other pages like like posts or share posts or hot posts are as the same as the codes beyond.
-
-
Hot search list
-
we show the 50th hottest posts in the hot post page
-
we define a formula to represent the hot: hot = comments * 1 + likes * 2 + favorites * 3 + shares * 4
-
when we need to get the hot posts, we filter in the query sentences.
@Select("select p.*, u.username authorname, v.username sendername, " + "(SELECT COUNT(*) FROM replies c WHERE c.topostid = p.postid) +\n" + "(SELECT COUNT(*) FROM likes l WHERE l.postid = p.postid) * 2 +\n" + "(SELECT COUNT(*) FROM favorites f WHERE f.postid = p.postid) * 3 +\n" + "(SELECT COUNT(*) FROM shares s WHERE s.postid = p.postid) * 4 AS hot\n" + "from posts p join users u on p.authorid = u.userid join users v on p.senderid = v.userid " + "and u.userID not in (select shieldID from shieldby where userID = #{userid})\n" + "and v.userID not in (select shieldID from shieldby where userID = #{userid})\n" + "order by hot desc;")
We get the hot of the post and rank the display in descending order based on the hot of the post
-
When we like or unlike and so on, we change the data of the front-end, then refresh the page, get hot posts from back-end again, complete the change of hot. Here is an example below.
toggleShare() { ... this.post.hot += 4; } toggleUnShare(){ ... this.post.hot -= 4; }
-
-
Multi-parameter search function
-
We allow the users to add plenty constraints as long as they want.
-
We can seach data by:
author
,sender
,postingTime
,title
,content
-
title
andcontent
support fuzzy search
How to seach the data by such restrictions?
-
back-end can get a series of restriction in
List<T>
-
use
.xml
configuration file to configurate SQL statement,foreach
is use to iterate theList
<foreach collection='author' item='item' index='index' separator=' OR '> authorname = #{item} </foreach>
-
To see more, please refer to the
findPostsByFilter
inPostMapper.java
-
-
Record the user login status
If the user does not login, webpage will be redirected to
localhost:8080/login
even if he want to access thelocalhost:8080/user/homepage
-
create
CookieManager
inutil
package, it store all static methods we use to manage thecookies
-
get cookies from
HttpServletRequest request
Cookie[] cookies = request.getCookies();
-
add/update the cookie to 1 hour
cookie.setMaxAge(60*60); cookie.setPath("/"); response.addCookie(cookie);
-
delete the cookie
cookie.setMaxAge(0); cookie.setPath("/"); response.addCookie(cookie);
-
-
IP analysis
The city of a post and country should not detemine by user, but how to get the city of the posting place?
-
add dependency in
pom.xml
<dependency> <groupId>com.maxmind.geoip2</groupId> <artifactId>geoip2</artifactId> <version>2.13.1</version> </dependency>
-
Search the ip in the front-end and wrap it in the data send to the back-end
axios.get('https://api.ipify.org?format=json',{withCredentials: false} ) .then(response => { ip = response.data.ip; }
-
install
Geaolite2-city.mmdb
-
use
Geaolite2-city.mmdb
to map an ip to a city
-
-
-
Technology stack introduction: (task 3 & 4 & 6)
- Backend:
springboot
- Front end:
vue2+vuex+vue-router+axios
- Component library:
element-ui
- Front-end and back-end connection test:
swagger 2
- Connection pool:
druid
- ORM:
Mybatis-plus
- POJO to json:
Jackson
advantage:
- Separation of front-end and back-end development: the back-end receives and verifies the front-end request, and then returns the data (Restful) required by the front-end in json format, and renders after the front-end gets the data.
- springboot: Adopting the method of convention over configuration, it provides developers with a very suitable environment for web development. At the same time, based on dependency injection(DI) and inversion of control transfer(IOC), it helps developers manage a series of tasks.
- Vue2: Progressive framework, easier to learn than react, two-way data binding, good at making single-page web pages.
- druid: The connection pool developed by Alibaba provides monitoring functions to clearly know the working conditions of the connection pool and SQL
- Mybatis-plus: On the basis of Mybatis, single-table query is enhanced, and SQL statements are bound through annotations or configuring
.xml
files
- Backend:
-
create index: (task 7)
To enhance the speed of Multi-parameter search function. At the same time, we find the length of the column
title
in tableposts
are always much shorter then thecontent
, hence we decide to create index in columntitle
CREATE INDEX title_index ON posts (title);