Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
springboot-mybatis
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wzy
springboot-mybatis
Commits
19daf2e5
Commit
19daf2e5
authored
May 08, 2021
by
wzy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
article
parent
ba74b150
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
852 additions
and
20 deletions
+852
-20
pom.xml
+14
-10
src/main/java/com/wzy/tacocloud/TacoCloudApplication.java
+0
-1
src/main/java/com/wzy/tacocloud/application/ArticleQueryService.java
+186
-0
src/main/java/com/wzy/tacocloud/application/article/ArticleCommandService.java
+43
-0
src/main/java/com/wzy/tacocloud/application/article/DuplicatedArticleConstraint.java
+17
-0
src/main/java/com/wzy/tacocloud/application/article/DuplicatedArticleValidator.java
+19
-0
src/main/java/com/wzy/tacocloud/application/article/NewArticleParam.java
+29
-0
src/main/java/com/wzy/tacocloud/application/article/UpdateArticleParam.java
+16
-0
src/main/java/com/wzy/tacocloud/application/user/UserService.java
+0
-1
src/main/java/com/wzy/tacocloud/controller/ArticleController.java
+89
-0
src/main/java/com/wzy/tacocloud/controller/UserController.java
+48
-7
src/main/java/com/wzy/tacocloud/controller/exception/CustomizeExceptionHandler.java
+110
-0
src/main/java/com/wzy/tacocloud/controller/exception/ErrorResource.java
+19
-0
src/main/java/com/wzy/tacocloud/controller/exception/ErrorResourceSerializer.java
+40
-0
src/main/java/com/wzy/tacocloud/controller/exception/FieldErrorResource.java
+21
-0
src/main/java/com/wzy/tacocloud/controller/exception/InvalidAuthenticationException.java
+8
-0
src/main/java/com/wzy/tacocloud/controller/exception/InvalidRequestException.java
+17
-0
src/main/java/com/wzy/tacocloud/core/article/Article.java
+69
-0
src/main/java/com/wzy/tacocloud/core/article/ArticleRepository.java
+15
-0
src/main/java/com/wzy/tacocloud/infrastructure/mybatis/mapper/ArticleMapper.java
+21
-0
src/main/resources/application.yml
+1
-1
src/main/resources/mapper/ArticleMapper.xml
+70
-0
No files found.
pom.xml
View file @
19daf2e5
...
...
@@ -22,6 +22,7 @@
</properties>
<dependencies>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-web
</artifactId>
...
...
@@ -29,6 +30,11 @@
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-validation
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-tomcat
</artifactId>
<scope>
provided
</scope>
</dependency>
...
...
@@ -55,26 +61,24 @@
<artifactId>
mybatis-spring-boot-starter
</artifactId>
<version>
2.1.4
</version>
</dependency>
<dependency>
<groupId>
jakarta.validation
</groupId>
<artifactId>
jakarta.validation-api
</artifactId>
<version>
2.0.1
</version>
</dependency>
<dependency>
<groupId>
javax.validation
</groupId>
<artifactId>
validation-api
</artifactId>
<version>
2.0.1.Final
</version>
</dependency>
<dependency>
<groupId>
org.projectlombok
</groupId>
<artifactId>
lombok
</artifactId>
</dependency>
<dependency>
<groupId>
io.jsonwebtoken
</groupId>
<artifactId>
jjwt
</artifactId>
<version>
0.9.1
</version>
</dependency>
<dependency>
<groupId>
joda-time
</groupId>
<artifactId>
joda-time
</artifactId>
<version>
2.10.6
</version>
</dependency>
</dependencies>
<build>
...
...
src/main/java/com/wzy/tacocloud/TacoCloudApplication.java
View file @
19daf2e5
...
...
@@ -2,7 +2,6 @@ package com.wzy.tacocloud;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
;
@SpringBootApplication
public
class
TacoCloudApplication
{
...
...
src/main/java/com/wzy/tacocloud/application/ArticleQueryService.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
application
;
import
io.spring.application.data.ArticleData
;
import
io.spring.application.data.ArticleDataList
;
import
io.spring.application.data.ArticleFavoriteCount
;
import
io.spring.core.user.User
;
import
io.spring.infrastructure.mybatis.readservice.ArticleFavoritesReadService
;
import
io.spring.infrastructure.mybatis.readservice.ArticleReadService
;
import
io.spring.infrastructure.mybatis.readservice.UserRelationshipQueryService
;
import
org.joda.time.DateTime
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
java.util.*
;
import
static
java
.
util
.
stream
.
Collectors
.
toList
;
@Service
public
class
ArticleQueryService
{
private
final
ArticleReadService
articleReadService
;
private
final
UserRelationshipQueryService
userRelationshipQueryService
;
private
final
ArticleFavoritesReadService
articleFavoritesReadService
;
@Autowired
public
ArticleQueryService
(
ArticleReadService
articleReadService
,
UserRelationshipQueryService
userRelationshipQueryService
,
ArticleFavoritesReadService
articleFavoritesReadService
)
{
this
.
articleReadService
=
articleReadService
;
this
.
userRelationshipQueryService
=
userRelationshipQueryService
;
this
.
articleFavoritesReadService
=
articleFavoritesReadService
;
}
public
Optional
<
ArticleData
>
findById
(
String
id
,
User
user
)
{
ArticleData
articleData
=
articleReadService
.
findById
(
id
);
if
(
articleData
==
null
)
{
return
Optional
.
empty
();
}
else
{
if
(
user
!=
null
)
{
fillExtraInfo
(
id
,
user
,
articleData
);
}
return
Optional
.
of
(
articleData
);
}
}
public
Optional
<
ArticleData
>
findBySlug
(
String
slug
,
User
user
)
{
ArticleData
articleData
=
articleReadService
.
findBySlug
(
slug
);
if
(
articleData
==
null
)
{
return
Optional
.
empty
();
}
else
{
if
(
user
!=
null
)
{
fillExtraInfo
(
articleData
.
getId
(),
user
,
articleData
);
}
return
Optional
.
of
(
articleData
);
}
}
public
CursorPager
<
ArticleData
>
findRecentArticlesWithCursor
(
String
tag
,
String
author
,
String
favoritedBy
,
CursorPageParameter
<
DateTime
>
page
,
User
currentUser
)
{
List
<
String
>
articleIds
=
articleReadService
.
findArticlesWithCursor
(
tag
,
author
,
favoritedBy
,
page
);
if
(
articleIds
.
size
()
==
0
)
{
return
new
CursorPager
<>(
new
ArrayList
<>(),
page
.
getDirection
(),
false
);
}
else
{
boolean
hasExtra
=
articleIds
.
size
()
>
page
.
getLimit
();
if
(
hasExtra
)
{
articleIds
.
remove
(
page
.
getLimit
());
}
if
(!
page
.
isNext
())
{
Collections
.
reverse
(
articleIds
);
}
List
<
ArticleData
>
articles
=
articleReadService
.
findArticles
(
articleIds
);
fillExtraInfo
(
articles
,
currentUser
);
return
new
CursorPager
<>(
articles
,
page
.
getDirection
(),
hasExtra
);
}
}
public
CursorPager
<
ArticleData
>
findUserFeedWithCursor
(
User
user
,
CursorPageParameter
<
DateTime
>
page
)
{
List
<
String
>
followdUsers
=
userRelationshipQueryService
.
followedUsers
(
user
.
getId
());
if
(
followdUsers
.
size
()
==
0
)
{
return
new
CursorPager
<>(
new
ArrayList
<>(),
page
.
getDirection
(),
false
);
}
else
{
List
<
ArticleData
>
articles
=
articleReadService
.
findArticlesOfAuthorsWithCursor
(
followdUsers
,
page
);
boolean
hasExtra
=
articles
.
size
()
>
page
.
getLimit
();
if
(
hasExtra
)
{
articles
.
remove
(
page
.
getLimit
());
}
if
(!
page
.
isNext
())
{
Collections
.
reverse
(
articles
);
}
fillExtraInfo
(
articles
,
user
);
return
new
CursorPager
<>(
articles
,
page
.
getDirection
(),
hasExtra
);
}
}
public
ArticleDataList
findRecentArticles
(
String
tag
,
String
author
,
String
favoritedBy
,
Page
page
,
User
currentUser
)
{
List
<
String
>
articleIds
=
articleReadService
.
queryArticles
(
tag
,
author
,
favoritedBy
,
page
);
int
articleCount
=
articleReadService
.
countArticle
(
tag
,
author
,
favoritedBy
);
if
(
articleIds
.
size
()
==
0
)
{
return
new
ArticleDataList
(
new
ArrayList
<>(),
articleCount
);
}
else
{
List
<
ArticleData
>
articles
=
articleReadService
.
findArticles
(
articleIds
);
fillExtraInfo
(
articles
,
currentUser
);
return
new
ArticleDataList
(
articles
,
articleCount
);
}
}
public
ArticleDataList
findUserFeed
(
User
user
,
Page
page
)
{
List
<
String
>
followdUsers
=
userRelationshipQueryService
.
followedUsers
(
user
.
getId
());
if
(
followdUsers
.
size
()
==
0
)
{
return
new
ArticleDataList
(
new
ArrayList
<>(),
0
);
}
else
{
List
<
ArticleData
>
articles
=
articleReadService
.
findArticlesOfAuthors
(
followdUsers
,
page
);
fillExtraInfo
(
articles
,
user
);
int
count
=
articleReadService
.
countFeedSize
(
followdUsers
);
return
new
ArticleDataList
(
articles
,
count
);
}
}
private
void
fillExtraInfo
(
List
<
ArticleData
>
articles
,
User
currentUser
)
{
setFavoriteCount
(
articles
);
if
(
currentUser
!=
null
)
{
setIsFavorite
(
articles
,
currentUser
);
setIsFollowingAuthor
(
articles
,
currentUser
);
}
}
private
void
setIsFollowingAuthor
(
List
<
ArticleData
>
articles
,
User
currentUser
)
{
Set
<
String
>
followingAuthors
=
userRelationshipQueryService
.
followingAuthors
(
currentUser
.
getId
(),
articles
.
stream
()
.
map
(
articleData1
->
articleData1
.
getProfileData
().
getId
())
.
collect
(
toList
()));
articles
.
forEach
(
articleData
->
{
if
(
followingAuthors
.
contains
(
articleData
.
getProfileData
().
getId
()))
{
articleData
.
getProfileData
().
setFollowing
(
true
);
}
});
}
private
void
setFavoriteCount
(
List
<
ArticleData
>
articles
)
{
List
<
ArticleFavoriteCount
>
favoritesCounts
=
articleFavoritesReadService
.
articlesFavoriteCount
(
articles
.
stream
().
map
(
ArticleData:
:
getId
).
collect
(
toList
()));
Map
<
String
,
Integer
>
countMap
=
new
HashMap
<>();
favoritesCounts
.
forEach
(
item
->
countMap
.
put
(
item
.
getId
(),
item
.
getCount
()));
articles
.
forEach
(
articleData
->
articleData
.
setFavoritesCount
(
countMap
.
get
(
articleData
.
getId
())));
}
private
void
setIsFavorite
(
List
<
ArticleData
>
articles
,
User
currentUser
)
{
Set
<
String
>
favoritedArticles
=
articleFavoritesReadService
.
userFavorites
(
articles
.
stream
().
map
(
ArticleData:
:
getId
).
collect
(
toList
()),
currentUser
);
articles
.
forEach
(
articleData
->
{
if
(
favoritedArticles
.
contains
(
articleData
.
getId
()))
{
articleData
.
setFavorited
(
true
);
}
});
}
private
void
fillExtraInfo
(
String
id
,
User
user
,
ArticleData
articleData
)
{
articleData
.
setFavorited
(
articleFavoritesReadService
.
isUserFavorite
(
user
.
getId
(),
id
));
articleData
.
setFavoritesCount
(
articleFavoritesReadService
.
articleFavoriteCount
(
id
));
articleData
.
getProfileData
()
.
setFollowing
(
userRelationshipQueryService
.
isUserFollowing
(
user
.
getId
(),
articleData
.
getProfileData
().
getId
()));
}
}
src/main/java/com/wzy/tacocloud/application/article/ArticleCommandService.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
application
.
article
;
import
io.spring.core.article.Article
;
import
io.spring.core.article.ArticleRepository
;
import
io.spring.core.user.User
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
org.springframework.validation.annotation.Validated
;
import
javax.validation.Valid
;
@Service
@Validated
public
class
ArticleCommandService
{
private
final
ArticleRepository
articleRepository
;
@Autowired
public
ArticleCommandService
(
ArticleRepository
articleRepository
)
{
this
.
articleRepository
=
articleRepository
;
}
public
Article
createArticle
(
@Valid
NewArticleParam
newArticleParam
,
User
creator
)
{
Article
article
=
new
Article
(
newArticleParam
.
getTitle
(),
newArticleParam
.
getDescription
(),
newArticleParam
.
getBody
(),
newArticleParam
.
getTagList
(),
creator
.
getId
());
articleRepository
.
save
(
article
);
return
article
;
}
public
Article
updateArticle
(
Article
article
,
@Valid
UpdateArticleParam
updateArticleParam
)
{
article
.
update
(
updateArticleParam
.
getTitle
(),
updateArticleParam
.
getDescription
(),
updateArticleParam
.
getBody
());
articleRepository
.
save
(
article
);
return
article
;
}
}
src/main/java/com/wzy/tacocloud/application/article/DuplicatedArticleConstraint.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
application
.
article
;
import
javax.validation.Constraint
;
import
javax.validation.Payload
;
import
java.lang.annotation.*
;
@Documented
@Constraint
(
validatedBy
=
DuplicatedArticleValidator
.
class
)
@Target
({
ElementType
.
METHOD
,
ElementType
.
FIELD
,
ElementType
.
PARAMETER
,
ElementType
.
TYPE_USE
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
DuplicatedArticleConstraint
{
String
message
()
default
"article name exists"
;
Class
<?>[]
groups
()
default
{};
Class
<?
extends
Payload
>[]
payload
()
default
{};
}
src/main/java/com/wzy/tacocloud/application/article/DuplicatedArticleValidator.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
application
.
article
;
import
io.spring.application.ArticleQueryService
;
import
io.spring.core.article.Article
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
javax.validation.ConstraintValidator
;
import
javax.validation.ConstraintValidatorContext
;
class
DuplicatedArticleValidator
implements
ConstraintValidator
<
io
.
spring
.
application
.
article
.
DuplicatedArticleConstraint
,
String
>
{
@Autowired
private
ArticleQueryService
articleQueryService
;
@Override
public
boolean
isValid
(
String
value
,
ConstraintValidatorContext
context
)
{
return
!
articleQueryService
.
findBySlug
(
Article
.
toSlug
(
value
),
null
).
isPresent
();
}
}
src/main/java/com/wzy/tacocloud/application/article/NewArticleParam.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
application
.
article
;
import
com.fasterxml.jackson.annotation.JsonRootName
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Getter
;
import
lombok.NoArgsConstructor
;
import
javax.validation.constraints.NotBlank
;
import
java.util.List
;
@Getter
@JsonRootName
(
"article"
)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public
class
NewArticleParam
{
@NotBlank
(
message
=
"can't be empty"
)
@io
.
spring
.
application
.
article
.
DuplicatedArticleConstraint
private
String
title
;
@NotBlank
(
message
=
"can't be empty"
)
private
String
description
;
@NotBlank
(
message
=
"can't be empty"
)
private
String
body
;
private
List
<
String
>
tagList
;
}
src/main/java/com/wzy/tacocloud/application/article/UpdateArticleParam.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
application
.
article
;
import
com.fasterxml.jackson.annotation.JsonRootName
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
import
lombok.NoArgsConstructor
;
@Getter
@NoArgsConstructor
@AllArgsConstructor
@JsonRootName
(
"article"
)
public
class
UpdateArticleParam
{
private
final
String
title
=
""
;
private
final
String
body
=
""
;
private
final
String
description
=
""
;
}
src/main/java/com/wzy/tacocloud/application/user/UserService.java
View file @
19daf2e5
...
...
@@ -6,7 +6,6 @@ import com.wzy.tacocloud.core.user.UserRepository;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
org.springframework.validation.annotation.Validated
;
import
javax.validation.Valid
;
@Service
...
...
src/main/java/com/wzy/tacocloud/controller/ArticleController.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
controller
;
import
io.spring.api.exception.NoAuthorizationException
;
import
io.spring.api.exception.ResourceNotFoundException
;
import
io.spring.application.ArticleQueryService
;
import
io.spring.application.article.ArticleCommandService
;
import
io.spring.application.article.UpdateArticleParam
;
import
io.spring.application.data.ArticleData
;
import
io.spring.core.article.ArticleRepository
;
import
io.spring.core.service.AuthorizationService
;
import
io.spring.core.user.User
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.security.core.annotation.AuthenticationPrincipal
;
import
org.springframework.web.bind.annotation.*
;
import
javax.validation.Valid
;
import
java.util.HashMap
;
import
java.util.Map
;
@RestController
@RequestMapping
(
path
=
"/articles/{slug}"
)
public
class
ArticleController
{
private
final
ArticleQueryService
articleQueryService
;
private
final
ArticleRepository
articleRepository
;
private
final
ArticleCommandService
articleCommandService
;
@Autowired
public
ArticleController
(
ArticleQueryService
articleQueryService
,
ArticleRepository
articleRepository
,
ArticleCommandService
articleCommandService
)
{
this
.
articleQueryService
=
articleQueryService
;
this
.
articleRepository
=
articleRepository
;
this
.
articleCommandService
=
articleCommandService
;
}
@GetMapping
public
ResponseEntity
<?>
article
(
@PathVariable
(
"slug"
)
String
slug
,
@AuthenticationPrincipal
User
user
)
{
return
articleQueryService
.
findBySlug
(
slug
,
user
)
.
map
(
articleData
->
ResponseEntity
.
ok
(
articleResponse
(
articleData
)))
.
orElseThrow
(
ResourceNotFoundException:
:
new
);
}
@PutMapping
public
ResponseEntity
<?>
updateArticle
(
@PathVariable
(
"slug"
)
String
slug
,
@AuthenticationPrincipal
User
user
,
@Valid
@RequestBody
UpdateArticleParam
updateArticleParam
)
{
return
articleRepository
.
findBySlug
(
slug
)
.
map
(
article
->
{
if
(!
AuthorizationService
.
canWriteArticle
(
user
,
article
))
{
throw
new
NoAuthorizationException
();
}
articleCommandService
.
updateArticle
(
article
,
updateArticleParam
);
return
ResponseEntity
.
ok
(
articleResponse
(
articleQueryService
.
findBySlug
(
slug
,
user
).
orElse
(
null
)));
})
.
orElseThrow
(
ResourceNotFoundException:
:
new
);
}
@DeleteMapping
public
ResponseEntity
<?>
deleteArticle
(
@PathVariable
(
"slug"
)
String
slug
,
@AuthenticationPrincipal
User
user
)
{
return
articleRepository
.
findBySlug
(
slug
)
.
map
(
article
->
{
if
(!
AuthorizationService
.
canWriteArticle
(
user
,
article
))
{
throw
new
NoAuthorizationException
();
}
articleRepository
.
remove
(
article
);
return
ResponseEntity
.
noContent
().
build
();
})
.
orElseThrow
(
ResourceNotFoundException:
:
new
);
}
private
Map
<
String
,
Object
>
articleResponse
(
ArticleData
articleData
)
{
return
new
HashMap
<
String
,
Object
>()
{
{
put
(
"article"
,
articleData
);
}
};
}
}
src/main/java/com/wzy/tacocloud/controller/UserController.java
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
controller
;
import
com.fasterxml.jackson.annotation.JsonRootName
;
import
com.wzy.tacocloud.application.UserQueryService
;
import
com.wzy.tacocloud.application.data.UserData
;
import
com.wzy.tacocloud.application.data.UserWithToken
;
import
com.wzy.tacocloud.application.user.RegisterParam
;
import
com.wzy.tacocloud.application.user.UserService
;
import
com.wzy.tacocloud.controller.exception.InvalidAuthenticationException
;
import
com.wzy.tacocloud.core.service.JwtService
;
import
com.wzy.tacocloud.core.user.EncryptService
;
import
com.wzy.tacocloud.core.user.User
;
import
com.wzy.tacocloud.application.user.UserService
;
import
com.wzy.tacocloud.core.user.UserRepository
;
import
lombok.Getter
;
import
lombok.NoArgsConstructor
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.ResponseEntity
;
import
javax.validation.Valid
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
javax.validation.Valid
;
import
javax.validation.constraints.NotBlank
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.Optional
;
import
static
org
.
springframework
.
web
.
bind
.
annotation
.
RequestMethod
.
POST
;
@RestController
public
class
UserController
{
//
private final UserRepository userRepository;
private
final
UserRepository
userRepository
;
private
final
UserService
userService
;
private
final
UserQueryService
userQueryService
;
private
final
JwtService
jwtService
;
private
final
EncryptService
encryptService
;
@Autowired
public
UserController
(
UserService
userService
,
UserQueryService
userQueryService
,
JwtService
jwtService
)
{
// this.userRepository = userRepository;
public
UserController
(
UserRepository
userRepository
,
UserService
userService
,
UserQueryService
userQueryService
,
JwtService
jwtService
,
EncryptService
encryptService
)
{
this
.
userRepository
=
userRepository
;
this
.
userService
=
userService
;
this
.
userQueryService
=
userQueryService
;
this
.
jwtService
=
jwtService
;
this
.
encryptService
=
encryptService
;
}
@RequestMapping
(
path
=
"/register"
,
method
=
POST
)
...
...
@@ -39,12 +51,40 @@ public class UserController {
User
user
=
userService
.
createUser
(
registerParam
);
UserData
userData
=
userQueryService
.
findById
(
user
.
getId
()).
orElse
(
null
);
assert
userData
!=
null
;
return
ResponseEntity
.
status
(
201
).
body
(
userResponse
(
new
UserWithToken
(
userData
,
jwtService
.
toToken
(
user
))));
return
ResponseEntity
.
status
(
201
)
.
body
(
userResponse
(
new
UserWithToken
(
userData
,
jwtService
.
toToken
(
user
))));
}
@RequestMapping
(
path
=
"/login"
,
method
=
POST
)
public
ResponseEntity
<?>
userLogin
(
@Valid
@RequestBody
LoginParam
loginParam
)
{
Optional
<
User
>
optional
=
userRepository
.
findByUsername
(
loginParam
.
getUsername
());
if
(
optional
.
isPresent
()
// 存在
&&
encryptService
.
check
(
loginParam
.
getPassword
(),
optional
.
get
().
getPassword
()))
{
UserData
userData
=
userQueryService
.
findById
(
optional
.
get
().
getId
()).
orElse
(
null
);
assert
userData
!=
null
;
return
ResponseEntity
.
ok
(
userResponse
(
new
UserWithToken
(
userData
,
jwtService
.
toToken
(
optional
.
get
()))));
}
else
{
throw
new
InvalidAuthenticationException
();
}
}
private
Map
<
String
,
Object
>
userResponse
(
UserWithToken
userWithToken
)
{
return
new
HashMap
<
String
,
Object
>()
{
{
put
(
"user"
,
userWithToken
);}
{
put
(
"user"
,
userWithToken
);
}
};
}
}
@Getter
@JsonRootName
(
"user"
)
@NoArgsConstructor
class
LoginParam
{
@NotBlank
(
message
=
"用户名不能为空"
)
private
String
username
;
@NotBlank
(
message
=
"密码不能为空"
)
private
String
password
;
}
\ No newline at end of file
src/main/java/com/wzy/tacocloud/controller/exception/CustomizeExceptionHandler.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
controller
.
exception
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.MethodArgumentNotValidException
;
import
org.springframework.web.bind.annotation.ExceptionHandler
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
org.springframework.web.bind.annotation.ResponseStatus
;
import
org.springframework.web.bind.annotation.RestControllerAdvice
;
import
org.springframework.web.context.request.WebRequest
;
import
org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
;
import
javax.validation.ConstraintViolation
;
import
javax.validation.ConstraintViolationException
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.stream.Collectors
;
import
static
org
.
springframework
.
http
.
HttpStatus
.
UNPROCESSABLE_ENTITY
;
@RestControllerAdvice
public
class
CustomizeExceptionHandler
extends
ResponseEntityExceptionHandler
{
@ExceptionHandler
({
InvalidRequestException
.
class
})
public
ResponseEntity
<
Object
>
handleInvalidRequest
(
RuntimeException
e
,
WebRequest
request
)
{
InvalidRequestException
ire
=
(
InvalidRequestException
)
e
;
List
<
FieldErrorResource
>
errorResources
=
ire
.
getErrors
().
getFieldErrors
().
stream
()
.
map
(
fieldError
->
new
FieldErrorResource
(
fieldError
.
getObjectName
(),
fieldError
.
getField
(),
fieldError
.
getCode
(),
fieldError
.
getDefaultMessage
()))
.
collect
(
Collectors
.
toList
());
ErrorResource
error
=
new
ErrorResource
(
errorResources
);
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_JSON
);
return
handleExceptionInternal
(
e
,
error
,
headers
,
UNPROCESSABLE_ENTITY
,
request
);
}
@ExceptionHandler
(
InvalidAuthenticationException
.
class
)
public
ResponseEntity
<
Object
>
handleInvalidAuthentication
(
InvalidAuthenticationException
e
,
WebRequest
request
)
{
return
ResponseEntity
.
status
(
UNPROCESSABLE_ENTITY
)
.
body
(
new
HashMap
<
String
,
Object
>()
{
{
put
(
"message"
,
e
.
getMessage
());
}
});
}
@Override
protected
ResponseEntity
<
Object
>
handleMethodArgumentNotValid
(
MethodArgumentNotValidException
e
,
HttpHeaders
headers
,
HttpStatus
status
,
WebRequest
request
)
{
List
<
FieldErrorResource
>
errorResources
=
e
.
getBindingResult
().
getFieldErrors
().
stream
()
.
map
(
fieldError
->
new
FieldErrorResource
(
fieldError
.
getObjectName
(),
fieldError
.
getField
(),
fieldError
.
getCode
(),
fieldError
.
getDefaultMessage
()))
.
collect
(
Collectors
.
toList
());
return
ResponseEntity
.
status
(
UNPROCESSABLE_ENTITY
).
body
(
new
ErrorResource
(
errorResources
));
}
@ExceptionHandler
({
ConstraintViolationException
.
class
})
@ResponseStatus
(
UNPROCESSABLE_ENTITY
)
@ResponseBody
public
ErrorResource
handleConstraintViolation
(
ConstraintViolationException
ex
,
WebRequest
request
)
{
List
<
FieldErrorResource
>
errors
=
new
ArrayList
<>();
for
(
ConstraintViolation
<?>
violation
:
ex
.
getConstraintViolations
())
{
FieldErrorResource
fieldErrorResource
=
new
FieldErrorResource
(
violation
.
getRootBeanClass
().
getName
(),
getParam
(
violation
.
getPropertyPath
().
toString
()),
violation
.
getConstraintDescriptor
().
getAnnotation
().
annotationType
().
getSimpleName
(),
violation
.
getMessage
());
errors
.
add
(
fieldErrorResource
);
}
return
new
ErrorResource
(
errors
);
}
private
String
getParam
(
String
s
)
{
String
[]
splits
=
s
.
split
(
"\\."
);
if
(
splits
.
length
==
1
)
{
return
s
;
}
else
{
return
String
.
join
(
"."
,
Arrays
.
copyOfRange
(
splits
,
2
,
splits
.
length
));
}
}
}
src/main/java/com/wzy/tacocloud/controller/exception/ErrorResource.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
controller
.
exception
;
import
com.fasterxml.jackson.annotation.JsonIgnoreProperties
;
import
com.fasterxml.jackson.annotation.JsonRootName
;
import
com.fasterxml.jackson.databind.annotation.JsonSerialize
;
import
java.util.List
;
@JsonSerialize
(
using
=
ErrorResourceSerializer
.
class
)
@JsonIgnoreProperties
(
ignoreUnknown
=
true
)
@lombok
.
Getter
@JsonRootName
(
"errors"
)
public
class
ErrorResource
{
private
List
<
FieldErrorResource
>
fieldErrors
;
public
ErrorResource
(
List
<
FieldErrorResource
>
fieldErrorResources
)
{
this
.
fieldErrors
=
fieldErrorResources
;
}
}
src/main/java/com/wzy/tacocloud/controller/exception/ErrorResourceSerializer.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
controller
.
exception
;
import
com.fasterxml.jackson.core.JsonGenerator
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.databind.JsonSerializer
;
import
com.fasterxml.jackson.databind.SerializerProvider
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
public
class
ErrorResourceSerializer
extends
JsonSerializer
<
ErrorResource
>
{
@Override
public
void
serialize
(
ErrorResource
value
,
JsonGenerator
gen
,
SerializerProvider
serializers
)
throws
IOException
,
JsonProcessingException
{
Map
<
String
,
List
<
String
>>
json
=
new
HashMap
<>();
gen
.
writeStartObject
();
gen
.
writeObjectFieldStart
(
"errors"
);
for
(
FieldErrorResource
fieldErrorResource
:
value
.
getFieldErrors
())
{
if
(!
json
.
containsKey
(
fieldErrorResource
.
getField
()))
{
json
.
put
(
fieldErrorResource
.
getField
(),
new
ArrayList
<
String
>());
}
json
.
get
(
fieldErrorResource
.
getField
()).
add
(
fieldErrorResource
.
getMessage
());
}
for
(
Map
.
Entry
<
String
,
List
<
String
>>
pair
:
json
.
entrySet
())
{
gen
.
writeArrayFieldStart
(
pair
.
getKey
());
pair
.
getValue
().
forEach
(
content
->
{
try
{
gen
.
writeString
(
content
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
});
gen
.
writeEndArray
();
}
gen
.
writeEndObject
();
gen
.
writeEndObject
();
}
}
src/main/java/com/wzy/tacocloud/controller/exception/FieldErrorResource.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
controller
.
exception
;
import
com.fasterxml.jackson.annotation.JsonIgnoreProperties
;
import
lombok.Getter
;
@JsonIgnoreProperties
(
ignoreUnknown
=
true
)
@Getter
public
class
FieldErrorResource
{
private
String
resource
;
private
String
field
;
private
String
code
;
private
String
message
;
public
FieldErrorResource
(
String
resource
,
String
field
,
String
code
,
String
message
)
{
this
.
resource
=
resource
;
this
.
field
=
field
;
this
.
code
=
code
;
this
.
message
=
message
;
}
}
src/main/java/com/wzy/tacocloud/controller/exception/InvalidAuthenticationException.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
controller
.
exception
;
public
class
InvalidAuthenticationException
extends
RuntimeException
{
public
InvalidAuthenticationException
()
{
super
(
"用户名或密码错误"
);
}
}
src/main/java/com/wzy/tacocloud/controller/exception/InvalidRequestException.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
controller
.
exception
;
import
org.springframework.validation.Errors
;
@SuppressWarnings
(
"serial"
)
public
class
InvalidRequestException
extends
RuntimeException
{
private
final
Errors
errors
;
public
InvalidRequestException
(
Errors
errors
)
{
super
(
""
);
this
.
errors
=
errors
;
}
public
Errors
getErrors
()
{
return
errors
;
}
}
src/main/java/com/wzy/tacocloud/core/article/Article.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
core
.
article
;
import
io.spring.Util
;
import
lombok.EqualsAndHashCode
;
import
lombok.Getter
;
import
lombok.NoArgsConstructor
;
import
org.joda.time.DateTime
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.UUID
;
import
static
java
.
util
.
stream
.
Collectors
.
toList
;
@Getter
@NoArgsConstructor
@EqualsAndHashCode
(
of
=
{
"id"
})
public
class
Article
{
private
String
userId
;
private
String
id
;
private
String
slug
;
private
String
title
;
private
String
description
;
private
String
body
;
private
DateTime
createdAt
;
private
DateTime
updatedAt
;
public
Article
(
String
title
,
String
description
,
String
body
,
List
<
String
>
tagList
,
String
userId
)
{
this
(
title
,
description
,
body
,
tagList
,
userId
,
new
DateTime
());
}
public
Article
(
String
title
,
String
description
,
String
body
,
List
<
String
>
tagList
,
String
userId
,
DateTime
createdAt
)
{
this
.
id
=
UUID
.
randomUUID
().
toString
();
this
.
slug
=
toSlug
(
title
);
this
.
title
=
title
;
this
.
description
=
description
;
this
.
body
=
body
;
this
.
userId
=
userId
;
this
.
createdAt
=
createdAt
;
this
.
updatedAt
=
createdAt
;
}
public
void
update
(
String
title
,
String
description
,
String
body
)
{
if
(!
Util
.
isEmpty
(
title
))
{
this
.
title
=
title
;
this
.
slug
=
toSlug
(
title
);
this
.
updatedAt
=
new
DateTime
();
}
if
(!
Util
.
isEmpty
(
description
))
{
this
.
description
=
description
;
this
.
updatedAt
=
new
DateTime
();
}
if
(!
Util
.
isEmpty
(
body
))
{
this
.
body
=
body
;
this
.
updatedAt
=
new
DateTime
();
}
}
public
static
String
toSlug
(
String
title
)
{
return
title
.
toLowerCase
().
replaceAll
(
"[&|\\uFE30-\\uFFA0’”\\s?,.]+"
,
"-"
);
}
}
src/main/java/com/wzy/tacocloud/core/article/ArticleRepository.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
core
.
article
;
import
java.util.Optional
;
public
interface
ArticleRepository
{
void
save
(
Article
article
);
Optional
<
Article
>
findById
(
String
id
);
Optional
<
Article
>
findBySlug
(
String
slug
);
void
remove
(
Article
article
);
}
src/main/java/com/wzy/tacocloud/infrastructure/mybatis/mapper/ArticleMapper.java
0 → 100644
View file @
19daf2e5
package
com
.
wzy
.
tacocloud
.
infrastructure
.
mybatis
.
mapper
;
import
io.spring.core.article.Article
;
import
io.spring.core.article.Tag
;
import
org.apache.ibatis.annotations.Mapper
;
import
org.apache.ibatis.annotations.Param
;
@Mapper
public
interface
ArticleMapper
{
void
insert
(
@Param
(
"article"
)
Article
article
);
Article
findById
(
@Param
(
"id"
)
String
id
);
void
insertArticleTagRelation
(
@Param
(
"articleId"
)
String
articleId
,
@Param
(
"tagId"
)
String
tagId
);
Article
findBySlug
(
@Param
(
"slug"
)
String
slug
);
void
update
(
@Param
(
"article"
)
Article
article
);
void
delete
(
@Param
(
"id"
)
String
id
);
}
src/main/resources/application.yml
View file @
19daf2e5
spring
:
datasource
:
driver-class-name
:
com.mysql.jdbc.Driver
driver-class-name
:
com.mysql.
cj.
jdbc.Driver
type
:
com.alibaba.druid.pool.DruidDataSource
url
:
jdbc:mysql://localhost:3306/taco_cloud?characterEncoding=utf8&useUnicode=true
username
:
root
...
...
src/main/resources/mapper/ArticleMapper.xml
0 → 100644
View file @
19daf2e5
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper
namespace=
"io.spring.infrastructure.mybatis.mapper.ArticleMapper"
>
<insert
id=
"insert"
>
insert into articles(id, slug, title, description, body, user_id, created_at, updated_at)
values(
#{article.id},
#{article.slug},
#{article.title},
#{article.description},
#{article.body},
#{article.userId},
#{article.createdAt},
#{article.updatedAt})
</insert>
<update
id=
"update"
>
update articles
<set>
<if
test=
"article.title != ''"
>
title = #{article.title},
</if>
<if
test=
"article.title != ''"
>
slug = #{article.slug},
</if>
<if
test=
"article.description != ''"
>
description = #{article.description},
</if>
<if
test=
"article.body != ''"
>
body = #{article.body}
</if>
</set>
where id = #{article.id}
</update>
<delete
id=
"delete"
>
delete from articles where id = #{id}
</delete>
<sql
id=
"selectArticle"
>
select
A.id articleId,
A.slug articleSlug,
A.title articleTitle,
A.description articleDescription,
A.body articleBody,
A.user_id articleUserId,
A.created_at articleCreatedAt,
A.updated_at articleUpdatedAt
from articles A
</sql>
<select
id=
"findById"
resultMap=
"article"
>
<include
refid=
"selectArticle"
/>
where A.id = #{id}
</select>
<select
id=
"findBySlug"
resultMap=
"article"
>
<include
refid=
"selectArticle"
/>
where A.slug = #{slug}
</select>
<resultMap
id=
"article"
type=
"io.spring.core.article.Article"
>
<id
column=
"articleId"
property=
"id"
/>
<result
column=
"articleUserId"
property=
"userId"
/>
<result
column=
"articleTitle"
property=
"title"
/>
<result
column=
"articleSlug"
property=
"slug"
/>
<result
column=
"articleDescription"
property=
"description"
/>
<result
column=
"articleBody"
property=
"body"
/>
<result
column=
"articleCreatedAt"
property=
"createdAt"
/>
<result
column=
"articleUpdatedAt"
property=
"updatedAt"
/>
<collection
property=
"tags"
ofType=
"arraylist"
resultMap=
"tag"
/>
</resultMap>
<resultMap
id=
"tag"
type=
"io.spring.core.article.Tag"
>
<id
column=
"tagId"
property=
"id"
/>
<result
column=
"tagName"
property=
"name"
/>
</resultMap>
</mapper>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment