Merge pull request #110 from ronger-x/master

🐛 编辑器上传文件使用 X-Upload-Token 请求头传递 token
This commit is contained in:
ronger 2022-10-30 22:49:45 +08:00 committed by GitHub
commit a97c4c3ee3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 252 additions and 367 deletions

View File

@ -8,7 +8,6 @@ import com.rymcu.forest.entity.User;
import com.rymcu.forest.enumerate.TransactionEnum;
import com.rymcu.forest.util.HttpUtils;
import com.rymcu.forest.util.UserUtils;
import com.rymcu.forest.web.api.exception.BaseApiException;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
@ -24,7 +23,7 @@ public class AnswerController {
private final static String ANSWER_API_URL = "http://1.116.175.112:8089/question";
@GetMapping("/today")
public GlobalResult today() throws BaseApiException {
public GlobalResult today() {
User user = UserUtils.getCurrentUserByToken();
String result = HttpUtils.sendGet(ANSWER_API_URL + "/record/" + user.getIdUser() );
return JSONObject.parseObject(result, GlobalResult.class);
@ -32,9 +31,9 @@ public class AnswerController {
@PostMapping("/answer")
@TransactionLogger(transactionType = TransactionEnum.Answer)
public GlobalResult answer(@RequestBody AnswerDTO answerDTO) throws BaseApiException {
public GlobalResult answer(@RequestBody AnswerDTO answerDTO) {
User user = UserUtils.getCurrentUserByToken();
Map params = new HashMap<>(3);
Map<String, Object> params = new HashMap<>(3);
params.put("userId", user.getIdUser());
params.put("answer", answerDTO.getAnswer());
params.put("subjectQuestionId", answerDTO.getIdSubjectQuestion());

View File

@ -1,31 +1,19 @@
package com.rymcu.forest.auth;
import com.rymcu.forest.dto.TokenUser;
import com.rymcu.forest.util.UserUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.UnauthenticatedException;
import java.util.Objects;
/**
* @author ronger
*/
public class BaseHashedCredentialsMatcher extends HashedCredentialsMatcher {
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
TokenModel tokenModel = (TokenModel) token;
String accessToken = (String) tokenModel.getCredentials();
if (StringUtils.isBlank(accessToken)) {
throw new UnauthenticatedException();
}
TokenUser tokenUser = UserUtils.getTokenUser(accessToken);
if (Objects.isNull(tokenUser)) {
throw new UnauthenticatedException();
}
UserUtils.getTokenUser(token.getCredentials().toString());
return true;
}
}

View File

@ -1,9 +1,12 @@
package com.rymcu.forest.auth;
import com.alibaba.fastjson2.JSONObject;
import com.rymcu.forest.core.result.GlobalResultGenerator;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.springframework.http.HttpStatus;
@ -31,8 +34,12 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
*/
@Override
protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
HttpServletRequest req = (HttpServletRequest) request;
String authorization = req.getHeader(JwtConstants.AUTHORIZATION);
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authorization = httpServletRequest.getHeader(JwtConstants.AUTHORIZATION);
if (StringUtils.isBlank(authorization)) {
// 编辑器上传文件使用 X-Upload-Token 请求头传递 token
authorization = httpServletRequest.getHeader(JwtConstants.UPLOAD_TOKEN);
}
return authorization != null;
}
@ -43,6 +50,10 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
protected boolean executeLogin(ServletRequest request, ServletResponse response) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authorization = httpServletRequest.getHeader(JwtConstants.AUTHORIZATION);
if (StringUtils.isBlank(authorization)) {
// 编辑器上传文件使用 X-Upload-Token 请求头传递 token
authorization = httpServletRequest.getHeader(JwtConstants.UPLOAD_TOKEN);
}
// 验证token
Claims claims;
try {
@ -72,14 +83,20 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
return false;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) {
if (isLoginAttempt(request, response)) {
try {
executeLogin(request, response);
return executeLogin(request, response);
} catch (Exception e) {
response401(request, response);
onLoginFail(response);
}
}
return true;
onLoginFail(response);
return false;
}
/**
@ -104,12 +121,12 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
/**
* 将非法请求跳转到 /401
*/
private void response401(ServletRequest request, ServletResponse response) {
private void onLoginFail(ServletResponse response) {
try {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
httpResponse.setContentType("application/json;charset=utf-8");
httpResponse.getOutputStream().write("login fail".getBytes());
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setContentType("application/json");
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.getOutputStream().write(JSONObject.toJSONString(GlobalResultGenerator.genErrorResult("未登录或已登录超时,请重新登录")).getBytes());
} catch (IOException e) {
// 错误日志
log.error(e.getMessage());

View File

@ -12,6 +12,7 @@ import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
@ -68,7 +69,7 @@ public class JwtRealm extends AuthorizingRealm {
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authToken) throws AuthenticationException {
TokenModel token = (TokenModel) authToken;
if (!manager.checkToken(token)) {
throw new AuthenticationException();
throw new UnauthorizedException();
}
return new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), this.getName());
}

View File

@ -7,8 +7,10 @@ import com.rymcu.forest.core.exception.TransactionException;
import com.rymcu.forest.core.result.GlobalResult;
import com.rymcu.forest.core.result.ResultCode;
import com.rymcu.forest.enumerate.TransactionCode;
import com.rymcu.forest.web.api.exception.BaseApiException;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
@ -39,19 +41,21 @@ public class BaseExceptionHandler {
@ExceptionHandler(Exception.class)
public Object errorHandler(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
if (isAjax(request)) {
GlobalResult result = new GlobalResult();
if (ex instanceof BaseApiException) {
result.setCode(((BaseApiException) ex).getCode());
result.setMessage(((BaseApiException) ex).getExtraMessage());
logger.info(result.getMessage());
} else if (ex instanceof UnauthenticatedException) {
result.setCode(1000001);
result.setMessage("token错误");
GlobalResult<ResultCode> result = new GlobalResult<>();
if (ex instanceof UnauthenticatedException) {
result = new GlobalResult<>(ResultCode.UNAUTHENTICATED);
logger.info("token错误");
} else if (ex instanceof UnauthorizedException) {
result.setCode(1000002);
result.setMessage("用户无权限");
result = new GlobalResult<>(ResultCode.UNAUTHORIZED);
logger.info("用户无权限");
} else if (ex instanceof UnknownAccountException) {
// 账号或密码错误
result = new GlobalResult<>(ResultCode.UNKNOWN_ACCOUNT);
logger.info(ex.getMessage());
} else if (ex instanceof AccountException) {
// 账号或密码错误
result = new GlobalResult<>(ResultCode.INCORRECT_ACCOUNT_OR_PASSWORD);
logger.info(ex.getMessage());
} else if (ex instanceof ServiceException) {
//业务失败的异常账号或密码错误
result.setCode(((ServiceException) ex).getCode());
@ -63,15 +67,15 @@ public class BaseExceptionHandler {
} else if (ex instanceof ServletException) {
result.setCode(ResultCode.FAIL.getCode());
result.setMessage(ex.getMessage());
} else if (ex instanceof BusinessException) {
result.setCode(ResultCode.FAIL.getCode());
result.setMessage(ex.getMessage());
} else if (ex instanceof TransactionException) {
result.setCode(TransactionCode.InsufficientBalance.getCode());
result.setCode(((TransactionException) ex).getCode());
result.setMessage(ex.getMessage());
} else if (ex instanceof BusinessException) {
result.setCode(ResultCode.INVALID_PARAM.getCode());
result.setMessage(ex.getMessage());
} else {
//系统内部异常,不返回给客户端,内部记录错误日志
result.setCode(ResultCode.INTERNAL_SERVER_ERROR.getCode());
result = new GlobalResult<>(ResultCode.INTERNAL_SERVER_ERROR);
String message;
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
@ -83,7 +87,6 @@ public class BaseExceptionHandler {
} else {
message = ex.getMessage();
}
result.setMessage("操作失败");
logger.error(message, ex);
}
result.setSuccess(false);
@ -92,15 +95,12 @@ public class BaseExceptionHandler {
ModelAndView mv = new ModelAndView();
FastJsonJsonView view = new FastJsonJsonView();
Map<String, Object> attributes = new HashMap(2);
if (ex instanceof BaseApiException) {
attributes.put("code", ((BaseApiException) ex).getCode());
attributes.put("message", ((BaseApiException) ex).getExtraMessage());
} else if (ex instanceof UnauthenticatedException) {
attributes.put("code", "1000001");
attributes.put("message", "token错误");
if (ex instanceof UnauthenticatedException) {
attributes.put("code", ResultCode.UNAUTHENTICATED.getCode());
attributes.put("message", ResultCode.UNAUTHENTICATED.getMessage());
} else if (ex instanceof UnauthorizedException) {
attributes.put("code", "1000002");
attributes.put("message", "用户无权限");
attributes.put("code", ResultCode.UNAUTHORIZED.getCode());
attributes.put("message", ResultCode.UNAUTHORIZED.getMessage());
} else if (ex instanceof ServiceException) {
//业务失败的异常账号或密码错误
attributes.put("code", ((ServiceException) ex).getCode());
@ -112,11 +112,11 @@ public class BaseExceptionHandler {
} else if (ex instanceof ServletException) {
attributes.put("code", ResultCode.FAIL.getCode());
attributes.put("message", ex.getMessage());
} else if (ex instanceof BusinessException) {
attributes.put("code", ResultCode.FAIL.getCode());
attributes.put("message", ex.getMessage());
} else if (ex instanceof TransactionException) {
attributes.put("code", TransactionCode.InsufficientBalance.getCode());
attributes.put("code", ((TransactionException) ex).getCode());
attributes.put("message", ex.getMessage());
} else if (ex instanceof BusinessException) {
attributes.put("code", ResultCode.INVALID_PARAM.getCode());
attributes.put("message", ex.getMessage());
} else {
//系统内部异常,不返回给客户端,内部记录错误日志
@ -133,7 +133,7 @@ public class BaseExceptionHandler {
message = ex.getMessage();
}
logger.error(message, ex);
attributes.put("message", "操作失败");
attributes.put("message", ResultCode.INTERNAL_SERVER_ERROR.getMessage());
}
attributes.put("success", false);
view.setAttributesMap(attributes);

View File

@ -34,7 +34,16 @@ public class ShiroConfig {
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
filterChainDefinitionMap.put("/api/v1/console/**", "anon");
filterChainDefinitionMap.put("/api/v1/article/detail/**", "anon");
filterChainDefinitionMap.put("/api/v1/topic/**", "anon");
filterChainDefinitionMap.put("/api/v1/user/**", "anon");
filterChainDefinitionMap.put("/api/v1/article/*/comments", "anon");
filterChainDefinitionMap.put("/api/v1/rule/currency/**", "anon");
filterChainDefinitionMap.put("/api/v1/lucene/**", "anon");
filterChainDefinitionMap.put("/api/v1/open-data/**", "anon");
filterChainDefinitionMap.put("/api/v1/auth/login/**", "anon");
filterChainDefinitionMap.put("/api/v1/auth/logout/**", "anon");
filterChainDefinitionMap.put("/api/v1/auth/refresh-token/**", "anon");
filterChainDefinitionMap.put("/**", "jwt");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

View File

@ -7,7 +7,7 @@ import com.rymcu.forest.core.result.ResultCode;
* 服务业务异常如 账号或密码错误 该异常只做INFO级别的日志记录 @see WebMvcConfigurer
* @author ronger
*/
public class ServiceException extends Exception {
public class ServiceException extends RuntimeException {
private int code;
private String extraMessage;

View File

@ -2,6 +2,9 @@ package com.rymcu.forest.core.result;
import lombok.Data;
/**
* @author ronger
*/
@Data
public class GlobalResult<T> {
private boolean success = false;
@ -12,6 +15,11 @@ public class GlobalResult<T> {
public GlobalResult() {
}
public GlobalResult(ResultCode resultCode) {
this.code = resultCode.getCode();
this.message = resultCode.getMessage();
}
public static <T> GlobalResult<T> newInstance() {
return new GlobalResult();
}

View File

@ -11,15 +11,21 @@ public enum ResultCode {
// 失败
FAIL(400, "访问失败"),
// 未认证签名错误
UNAUTHORIZED(401, "签名错误"),
UNAUTHENTICATED(401, "签名错误"),
// 未认证签名错误
UNAUTHORIZED(403, "用户无权限"),
// 接口不存在
NOT_FOUND(404, "此接口不存在"),
// 服务器内部错误
INTERNAL_SERVER_ERROR(500, "系统繁忙,请稍后再试"),
// 参数错误
INVALID_PARAM(10000, "参数错误");
private int code;
private String message;
INVALID_PARAM(10000, "参数错误"),
// 未知账号
UNKNOWN_ACCOUNT(10001, "未知账号"),
// 账号或密码错误
INCORRECT_ACCOUNT_OR_PASSWORD(10002, "账号或密码错误");
private final int code;
private final String message;
ResultCode(int code, String message) {
this.code = code;

View File

@ -3,6 +3,7 @@ package com.rymcu.forest.core.service.security;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.rymcu.forest.auth.JwtConstants;
import com.rymcu.forest.core.exception.BusinessException;
import com.rymcu.forest.core.service.security.annotation.AuthorshipInterceptor;
import com.rymcu.forest.dto.TokenUser;
import com.rymcu.forest.entity.Article;
@ -12,9 +13,8 @@ import com.rymcu.forest.mapper.UserMapper;
import com.rymcu.forest.service.ArticleService;
import com.rymcu.forest.service.PortfolioService;
import com.rymcu.forest.util.UserUtils;
import com.rymcu.forest.web.api.exception.BaseApiException;
import com.rymcu.forest.web.api.exception.ErrorCode;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@ -64,7 +64,7 @@ public class AuthorshipAspect {
* @throws Throwable 调用出错
*/
@Before(value = "authorshipPointCut()")
public void doBefore(JoinPoint joinPoint) throws BaseApiException {
public void doBefore(JoinPoint joinPoint) {
logger.info("检查作者身份 start ...");
String methodName = joinPoint.getSignature().getName();
Method method = currentMethod(joinPoint, methodName);
@ -75,7 +75,7 @@ public class AuthorshipAspect {
isArticle = false;
}
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
String idArticle;
String id;
Long idAuthor = 0L;
if (isAjax(request)) {
Object[] objects = joinPoint.getArgs();
@ -92,14 +92,14 @@ public class AuthorshipAspect {
}
if (Objects.nonNull(jsonObject)) {
if (isArticle) {
idArticle = jsonObject.getString("idArticle");
Article article = articleService.findById(idArticle);
id = jsonObject.getString("idArticle");
Article article = articleService.findById(id);
if (Objects.nonNull(article)) {
idAuthor = article.getArticleAuthorId();
}
} else {
idArticle = jsonObject.getString("idPortfolio");
Portfolio portfolio = portfolioService.findById(idArticle);
id = jsonObject.getString("idPortfolio");
Portfolio portfolio = portfolioService.findById(id);
if (Objects.nonNull(portfolio)) {
idAuthor = portfolio.getPortfolioAuthorId();
}
@ -113,14 +113,14 @@ public class AuthorshipAspect {
params.putAll((Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE));
}
if (isArticle) {
idArticle = (String) params.get("idArticle");
Article article = articleService.findById(idArticle);
id = (String) params.get("idArticle");
Article article = articleService.findById(id);
if (Objects.nonNull(article)) {
idAuthor = article.getArticleAuthorId();
}
} else {
idArticle = (String) params.get("idPortfolio");
Portfolio portfolio = portfolioService.findById(idArticle);
id = (String) params.get("idPortfolio");
Portfolio portfolio = portfolioService.findById(id);
if (Objects.nonNull(portfolio)) {
idAuthor = portfolio.getPortfolioAuthorId();
}
@ -130,23 +130,19 @@ public class AuthorshipAspect {
String authHeader = request.getHeader(JwtConstants.AUTHORIZATION);
if (StringUtils.isNotBlank(authHeader)) {
TokenUser tokenUser = UserUtils.getTokenUser(authHeader);
if (Objects.nonNull(tokenUser)) {
if (!idAuthor.equals(tokenUser.getIdUser())) {
boolean hasPermission = false;
if (Module.ARTICLE_TAG.equals(log.moduleName())) {
// 判断管理员权限
hasPermission = userMapper.hasAdminPermission(tokenUser.getAccount());
}
if (!hasPermission) {
throw new BaseApiException(ErrorCode.ACCESS_DENIED);
}
if (!idAuthor.equals(tokenUser.getIdUser())) {
boolean hasPermission = false;
if (Module.ARTICLE_TAG.equals(log.moduleName())) {
// 判断管理员权限
hasPermission = userMapper.hasAdminPermission(tokenUser.getAccount());
}
if (!hasPermission) {
throw new UnauthorizedException();
}
} else {
throw new BaseApiException(ErrorCode.ACCESS_DENIED);
}
}
} else {
throw new BaseApiException(ErrorCode.ACCESS_DENIED);
throw new BusinessException("参数异常");
}
}
logger.info("检查作者身份 end ...");

View File

@ -5,9 +5,9 @@ import com.alibaba.fastjson.JSONObject;
import com.rymcu.forest.auth.JwtConstants;
import com.rymcu.forest.dto.TokenUser;
import com.rymcu.forest.util.UserUtils;
import com.rymcu.forest.web.api.exception.BaseApiException;
import com.rymcu.forest.web.api.exception.ErrorCode;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@ -48,7 +48,7 @@ public class SecurityAspect {
* @throws Throwable 调用出错
*/
@Before(value = "securityPointCut()")
public void doBefore(JoinPoint joinPoint) throws BaseApiException {
public void doBefore(JoinPoint joinPoint) {
logger.info("检查用户修改信息权限 start ...");
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String idUser = "";
@ -76,16 +76,12 @@ public class SecurityAspect {
String authHeader = request.getHeader(JwtConstants.AUTHORIZATION);
if (StringUtils.isNotBlank(authHeader)) {
TokenUser tokenUser = UserUtils.getTokenUser(authHeader);
if (Objects.nonNull(tokenUser)) {
if (!idUser.equals(tokenUser.getIdUser().toString())) {
throw new BaseApiException(ErrorCode.ACCESS_DENIED);
}
} else {
throw new BaseApiException(ErrorCode.ACCESS_DENIED);
if (!idUser.equals(tokenUser.getIdUser().toString())) {
throw new UnauthorizedException();
}
}
} else {
throw new BaseApiException(ErrorCode.ACCESS_DENIED);
throw new UnauthenticatedException();
}
logger.info("检查用户修改信息权限 end ...");
}

View File

@ -3,7 +3,6 @@ package com.rymcu.forest.enumerate;
/**
* @author ronger
*/
public enum TransactionCode {
InsufficientBalance(901, "余额不足");
@ -17,7 +16,6 @@ public enum TransactionCode {
this.message = message;
}
public String getMessage() {
return this.message;
}

View File

@ -5,7 +5,6 @@ import java.util.Arrays;
/**
* @author ronger
*/
public enum TransactionEnum {
ArticleSponsor(20, "文章赞赏"),
Answer(30, "答题奖励"),

View File

@ -47,10 +47,12 @@ public interface NotificationMapper extends Mapper<Notification> {
/**
* 标记消息已读
*
* @param id
* @param idUser
* @return
*/
Integer readNotification(@Param("id") Long id);
Integer readNotification(@Param("id") Long id, Long idUser);
/**
* 标记所有消息已读

View File

@ -5,7 +5,6 @@ import com.rymcu.forest.dto.ArticleDTO;
import com.rymcu.forest.dto.ArticleSearchDTO;
import com.rymcu.forest.entity.Article;
import com.rymcu.forest.entity.User;
import com.rymcu.forest.web.api.exception.BaseApiException;
import java.io.UnsupportedEncodingException;
import java.util.List;
@ -56,18 +55,16 @@ public interface ArticleService extends Service<Article> {
* @param article
* @param user
* @throws UnsupportedEncodingException
* @throws BaseApiException
* @return
* */
Long postArticle(ArticleDTO article, User user) throws UnsupportedEncodingException, BaseApiException;
Long postArticle(ArticleDTO article, User user) throws UnsupportedEncodingException;
/**
* 删除文章
* @param id
* @return
* @throws BaseApiException
* */
Integer delete(Long id) throws BaseApiException;
Integer delete(Long id);
/**
* 增量文章浏览数
@ -77,11 +74,12 @@ public interface ArticleService extends Service<Article> {
/**
* 获取分享链接数据
*
* @param id
* @throws BaseApiException
* @param account
* @return
*/
String share(Integer id) throws BaseApiException;
String share(Integer id, String account);
/**
* 查询草稿文章类别
@ -112,9 +110,8 @@ public interface ArticleService extends Service<Article> {
* @param userId
* @return
* @throws UnsupportedEncodingException
* @throws BaseApiException
*/
Boolean updateTags(Long idArticle, String tags, Long userId) throws UnsupportedEncodingException, BaseApiException;
Boolean updateTags(Long idArticle, String tags, Long userId) throws UnsupportedEncodingException;
/**
* 更新文章优选状态

View File

@ -3,7 +3,6 @@ package com.rymcu.forest.service;
import com.rymcu.forest.core.service.Service;
import com.rymcu.forest.dto.UserDTO;
import com.rymcu.forest.entity.Follow;
import com.rymcu.forest.web.api.exception.BaseApiException;
import java.util.List;
@ -13,28 +12,29 @@ import java.util.List;
public interface FollowService extends Service<Follow> {
/**
* 判断是否关注
*
* @param followingId
* @param followingType
* @param idUser
* @return
* @throws BaseApiException
*/
Boolean isFollow(Integer followingId, String followingType) throws BaseApiException;
Boolean isFollow(Integer followingId, String followingType, Long idUser);
/**
* 关注操作
*
* @param follow
* @param nickname
* @return
* @throws BaseApiException
*/
Boolean follow(Follow follow) throws BaseApiException;
Boolean follow(Follow follow, String nickname);
/**
* 取消关注操作
* @param follow
* @return
* @throws BaseApiException
*/
Boolean cancelFollow(Follow follow) throws BaseApiException;
Boolean cancelFollow(Follow follow);
/**
* 获取关注用户者数据

View File

@ -3,7 +3,6 @@ package com.rymcu.forest.service;
import com.rymcu.forest.core.service.Service;
import com.rymcu.forest.dto.NotificationDTO;
import com.rymcu.forest.entity.Notification;
import com.rymcu.forest.web.api.exception.BaseApiException;
import java.util.List;
@ -47,17 +46,18 @@ public interface NotificationService extends Service<Notification> {
/**
* 标记消息已读
*
* @param id
* @param idUser
* @return
*/
Integer readNotification(Long id);
Integer readNotification(Long id, Long idUser);
/**
* 标记所有消息已读
* @return
* @throws BaseApiException
*/
Integer readAllNotification() throws BaseApiException;
Integer readAllNotification();
/**
* 删除相关未读消息

View File

@ -8,7 +8,6 @@ import com.rymcu.forest.dto.PortfolioArticleDTO;
import com.rymcu.forest.dto.PortfolioDTO;
import com.rymcu.forest.dto.UserDTO;
import com.rymcu.forest.entity.Portfolio;
import com.rymcu.forest.web.api.exception.BaseApiException;
import java.util.List;
@ -34,7 +33,6 @@ public interface PortfolioService extends Service<Portfolio> {
/**
* 保持/更新作品集
* @param portfolio
* @throws BaseApiException
* @return
*/
Portfolio postPortfolio(Portfolio portfolio);

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.service;
import com.rymcu.forest.core.exception.ServiceException;
import com.rymcu.forest.core.service.Service;
import com.rymcu.forest.entity.Sponsor;
@ -12,7 +13,7 @@ public interface SponsorService extends Service<Sponsor> {
*
* @param sponsor
* @return
* @throws Exception
* @throws ServiceException
*/
boolean sponsorship(Sponsor sponsor) throws Exception;
boolean sponsorship(Sponsor sponsor) throws ServiceException;
}

View File

@ -4,7 +4,6 @@ import com.rymcu.forest.core.service.Service;
import com.rymcu.forest.dto.LabelModel;
import com.rymcu.forest.entity.Article;
import com.rymcu.forest.entity.Tag;
import com.rymcu.forest.web.api.exception.BaseApiException;
import java.io.UnsupportedEncodingException;
import java.util.List;
@ -19,10 +18,9 @@ public interface TagService extends Service<Tag> {
* @param article
* @param articleContentHtml
* @throws UnsupportedEncodingException
* @throws BaseApiException
* @return
* */
Integer saveTagArticle(Article article, String articleContentHtml, Long userId) throws UnsupportedEncodingException, BaseApiException;
Integer saveTagArticle(Article article, String articleContentHtml, Long userId) throws UnsupportedEncodingException;
/**
* 清除未使用标签

View File

@ -18,11 +18,8 @@ import com.rymcu.forest.service.NotificationService;
import com.rymcu.forest.service.TagService;
import com.rymcu.forest.service.UserService;
import com.rymcu.forest.util.Html2TextUtil;
import com.rymcu.forest.util.UserUtils;
import com.rymcu.forest.util.Utils;
import com.rymcu.forest.util.XssUtils;
import com.rymcu.forest.web.api.exception.BaseApiException;
import com.rymcu.forest.web.api.exception.ErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
@ -106,8 +103,8 @@ public class ArticleServiceImpl extends AbstractService<Article> implements Arti
}
@Override
@Transactional(rollbackFor = {UnsupportedEncodingException.class, BaseApiException.class})
public Long postArticle(ArticleDTO article, User user) throws UnsupportedEncodingException, BaseApiException {
@Transactional(rollbackFor = {UnsupportedEncodingException.class})
public Long postArticle(ArticleDTO article, User user) throws UnsupportedEncodingException {
boolean isUpdate = false;
String articleTitle = article.getArticleTitle();
String articleTags = article.getArticleTags();
@ -178,7 +175,7 @@ public class ArticleServiceImpl extends AbstractService<Article> implements Arti
@Override
@Transactional(rollbackFor = Exception.class)
public Integer delete(Long id) throws BaseApiException {
public Integer delete(Long id) {
// 判断是否有评论
if (!articleMapper.existsCommentWithPrimaryKey(id)) {
// 删除关联数据(作品集关联关系,标签关联关系)
@ -214,13 +211,9 @@ public class ArticleServiceImpl extends AbstractService<Article> implements Arti
}
@Override
public String share(Integer id) throws BaseApiException {
public String share(Integer id, String account) {
Article article = articleMapper.selectByPrimaryKey(id);
User user = UserUtils.getCurrentUserByToken();
if (Objects.isNull(user)) {
throw new BaseApiException(ErrorCode.INVALID_TOKEN);
}
return article.getArticlePermalink() + "?s=" + user.getAccount();
return article.getArticlePermalink() + "?s=" + account;
}
@Override
@ -246,7 +239,7 @@ public class ArticleServiceImpl extends AbstractService<Article> implements Arti
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateTags(Long idArticle, String tags, Long userId) throws UnsupportedEncodingException, BaseApiException {
public Boolean updateTags(Long idArticle, String tags, Long userId) throws UnsupportedEncodingException {
Article article = articleMapper.selectByPrimaryKey(idArticle);
if (!Objects.nonNull(article)) {
throw new ContentNotExistException("更新失败,文章不存在!");

View File

@ -4,12 +4,9 @@ import com.rymcu.forest.core.constant.NotificationConstant;
import com.rymcu.forest.core.service.AbstractService;
import com.rymcu.forest.dto.UserDTO;
import com.rymcu.forest.entity.Follow;
import com.rymcu.forest.entity.User;
import com.rymcu.forest.mapper.FollowMapper;
import com.rymcu.forest.service.FollowService;
import com.rymcu.forest.util.NotificationUtils;
import com.rymcu.forest.util.UserUtils;
import com.rymcu.forest.web.api.exception.BaseApiException;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@ -25,27 +22,21 @@ public class FollowServiceImpl extends AbstractService<Follow> implements Follow
private FollowMapper followMapper;
@Override
public Boolean isFollow(Integer followingId, String followingType) throws BaseApiException {
User tokenUser = UserUtils.getCurrentUserByToken();
Boolean b = followMapper.isFollow(followingId, tokenUser.getIdUser(), followingType);
return b;
public Boolean isFollow(Integer followingId, String followingType, Long idUser) {
return followMapper.isFollow(followingId, idUser, followingType);
}
@Override
public Boolean follow(Follow follow) throws BaseApiException {
User tokenUser = UserUtils.getCurrentUserByToken();
follow.setFollowerId(tokenUser.getIdUser());
public Boolean follow(Follow follow, String nickname) {
int result = followMapper.insertSelective(follow);
if (result > 0) {
NotificationUtils.saveNotification(follow.getFollowingId(), follow.getIdFollow(), NotificationConstant.Follow, tokenUser.getNickname() + " 关注了你!");
NotificationUtils.saveNotification(follow.getFollowingId(), follow.getIdFollow(), NotificationConstant.Follow, nickname + " 关注了你!");
}
return result > 0;
}
@Override
public Boolean cancelFollow(Follow follow) throws BaseApiException {
User tokenUser = UserUtils.getCurrentUserByToken();
follow.setFollowerId(tokenUser.getIdUser());
public Boolean cancelFollow(Follow follow) {
int result = followMapper.delete(follow);
return result == 0;
}
@ -60,13 +51,11 @@ public class FollowServiceImpl extends AbstractService<Follow> implements Follow
@Override
public List<UserDTO> findUserFollowersByUser(UserDTO userDTO) {
List<UserDTO> list = followMapper.selectUserFollowersByUser(userDTO.getIdUser());
return list;
return followMapper.selectUserFollowersByUser(userDTO.getIdUser());
}
@Override
public List<UserDTO> findUserFollowingsByUser(UserDTO userDTO) {
List<UserDTO> list = followMapper.selectUserFollowingsByUser(userDTO.getIdUser());
return list;
return followMapper.selectUserFollowingsByUser(userDTO.getIdUser());
}
}

View File

@ -8,7 +8,6 @@ import com.rymcu.forest.service.NotificationService;
import com.rymcu.forest.util.BeanCopierUtil;
import com.rymcu.forest.util.NotificationUtils;
import com.rymcu.forest.util.UserUtils;
import com.rymcu.forest.web.api.exception.BaseApiException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -43,7 +42,7 @@ public class NotificationServiceImpl extends AbstractService<Notification> imple
} else {
// 关联数据已删除,且未读
if (UN_READ.equals(notification.getHasRead())) {
notificationMapper.readNotification(notification.getIdNotification());
notificationMapper.readNotification(notification.getIdNotification(), idUser);
}
NotificationDTO dto = new NotificationDTO();
dto.setDataSummary("该消息已被撤销!");
@ -69,12 +68,12 @@ public class NotificationServiceImpl extends AbstractService<Notification> imple
@Override
@Transactional(rollbackFor = Exception.class)
public Integer readNotification(Long id) {
return notificationMapper.readNotification(id);
public Integer readNotification(Long id, Long idUser) {
return notificationMapper.readNotification(id, idUser);
}
@Override
public Integer readAllNotification() throws BaseApiException {
public Integer readAllNotification() {
return notificationMapper.readAllNotification(Objects.requireNonNull(UserUtils.getCurrentUserByToken()).getIdUser());
}

View File

@ -35,8 +35,8 @@ public class SponsorServiceImpl extends AbstractService<Sponsor> implements Spon
private TransactionRecordService transactionRecordService;
@Override
@Transactional(rollbackFor = Exception.class)
public boolean sponsorship(Sponsor sponsor) throws Exception {
@Transactional(rollbackFor = ServiceException.class)
public boolean sponsorship(Sponsor sponsor) throws ServiceException {
TransactionEnum transactionEnum = TransactionEnum.findTransactionEnum(sponsor.getDataType());
BigDecimal money = BigDecimal.valueOf(transactionEnum.getMoney());
sponsor.setSponsorshipMoney(money);

View File

@ -15,7 +15,6 @@ import com.rymcu.forest.mapper.TagMapper;
import com.rymcu.forest.service.TagService;
import com.rymcu.forest.util.XssUtils;
import com.rymcu.forest.web.api.common.UploadController;
import com.rymcu.forest.web.api.exception.BaseApiException;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -41,8 +40,8 @@ public class TagServiceImpl extends AbstractService<Tag> implements TagService {
private RedisService redisService;
@Override
@Transactional(rollbackFor = {UnsupportedEncodingException.class, BaseApiException.class})
public Integer saveTagArticle(Article article, String articleContentHtml, Long userId) throws UnsupportedEncodingException, BaseApiException {
@Transactional(rollbackFor = {UnsupportedEncodingException.class})
public Integer saveTagArticle(Article article, String articleContentHtml, Long userId) throws UnsupportedEncodingException {
String articleTags = article.getArticleTags();
if (StringUtils.isNotBlank(articleTags)) {
String[] tags = articleTags.split(",");

View File

@ -20,8 +20,8 @@ import com.rymcu.forest.util.Utils;
import com.rymcu.forest.web.api.common.UploadController;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.exceptions.TooManyResultsException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
@ -130,12 +130,9 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
// 保存登录日志
loginRecordService.saveLoginRecord(user.getIdUser());
return tokenUser;
} else {
throw new AuthenticationException("密码错误");
}
} else {
throw new UnknownAccountException("账号不存在");
}
throw new AccountException();
}
@Override
@ -316,11 +313,9 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
redisTemplate.boundValueOps(tokenUser.getRefreshToken()).set(account, JwtConstants.REFRESH_TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
redisTemplate.delete(refreshToken);
return tokenUser;
} else {
throw new UnknownAccountException("未知账号");
}
}
return null;
throw new UnauthenticatedException();
}
@Override

View File

@ -10,6 +10,7 @@ import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureException;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import java.util.Objects;
@ -19,8 +20,8 @@ import java.util.Objects;
*/
public class UserUtils {
private static UserMapper userMapper = SpringContextHolder.getBean(UserMapper.class);
private static TokenManager tokenManager = SpringContextHolder.getBean(TokenManager.class);
private static final UserMapper userMapper = SpringContextHolder.getBean(UserMapper.class);
private static final TokenManager tokenManager = SpringContextHolder.getBean(TokenManager.class);
/**
* 通过token获取当前用户的信息
@ -30,25 +31,26 @@ public class UserUtils {
public static User getCurrentUserByToken() {
String authHeader = ContextHolderUtils.getRequest().getHeader(JwtConstants.AUTHORIZATION);
if (authHeader == null) {
return null;
throw new UnauthenticatedException();
}
// 验证token
Claims claims;
try {
claims = Jwts.parser().setSigningKey(JwtConstants.JWT_SECRET).parseClaimsJws(authHeader).getBody();
} catch (final SignatureException e) {
throw new UnauthorizedException();
throw new UnauthenticatedException();
}
Object account = claims.getId();
if (StringUtils.isNotBlank(Objects.toString(account, ""))) {
TokenModel model = tokenManager.getToken(authHeader, account.toString());
if (tokenManager.checkToken(model)) {
return userMapper.selectByAccount(account.toString());
User user = userMapper.selectByAccount(account.toString());
if (Objects.nonNull(user)) {
return user;
}
}
} else {
throw new UnauthorizedException();
}
return null;
throw new UnauthenticatedException();
}
public static TokenUser getTokenUser(String token) {
@ -58,14 +60,14 @@ public class UserUtils {
try {
claims = Jwts.parser().setSigningKey(JwtConstants.JWT_SECRET).parseClaimsJws(token).getBody();
} catch (final SignatureException e) {
return null;
throw new UnauthenticatedException();
}
Object account = claims.getId();
if (StringUtils.isNotBlank(Objects.toString(account, ""))) {
TokenModel model = tokenManager.getToken(token, account.toString());
if (tokenManager.checkToken(model)) {
User user = userMapper.selectByAccount(account.toString());
if (user != null) {
if (Objects.nonNull(user)) {
TokenUser tokenUser = new TokenUser();
BeanCopierUtil.copy(user, tokenUser);
tokenUser.setAccount(user.getEmail());
@ -75,6 +77,6 @@ public class UserUtils {
}
}
}
return null;
throw new UnauthenticatedException();
}
}

View File

@ -18,8 +18,6 @@ import com.rymcu.forest.service.ArticleThumbsUpService;
import com.rymcu.forest.service.CommentService;
import com.rymcu.forest.service.SponsorService;
import com.rymcu.forest.util.UserUtils;
import com.rymcu.forest.web.api.exception.BaseApiException;
import com.rymcu.forest.web.api.exception.ErrorCode;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@ -50,27 +48,21 @@ public class ArticleController {
}
@PostMapping("/post")
public GlobalResult<Long> postArticle(@RequestBody ArticleDTO article) throws BaseApiException, UnsupportedEncodingException {
public GlobalResult<Long> postArticle(@RequestBody ArticleDTO article) throws UnsupportedEncodingException {
User user = UserUtils.getCurrentUserByToken();
if (Objects.isNull(user)) {
throw new BaseApiException(ErrorCode.INVALID_TOKEN);
}
return GlobalResultGenerator.genSuccessResult(articleService.postArticle(article, user));
}
@PutMapping("/post")
@AuthorshipInterceptor(moduleName = Module.ARTICLE)
public GlobalResult<Long> updateArticle(@RequestBody ArticleDTO article) throws BaseApiException, UnsupportedEncodingException {
public GlobalResult<Long> updateArticle(@RequestBody ArticleDTO article) throws UnsupportedEncodingException {
User user = UserUtils.getCurrentUserByToken();
if (Objects.isNull(user)) {
throw new BaseApiException(ErrorCode.INVALID_TOKEN);
}
return GlobalResultGenerator.genSuccessResult(articleService.postArticle(article, user));
}
@DeleteMapping("/delete/{idArticle}")
@AuthorshipInterceptor(moduleName = Module.ARTICLE)
public GlobalResult<Integer> delete(@PathVariable Long idArticle) throws BaseApiException {
public GlobalResult<Integer> delete(@PathVariable Long idArticle) {
return GlobalResultGenerator.genSuccessResult(articleService.delete(idArticle));
}
@ -80,25 +72,23 @@ public class ArticleController {
}
@GetMapping("/drafts")
public GlobalResult<PageInfo<ArticleDTO>> drafts(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows) throws BaseApiException {
public GlobalResult<PageInfo<ArticleDTO>> drafts(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows) {
PageHelper.startPage(page, rows);
User user = UserUtils.getCurrentUserByToken();
if (Objects.isNull(user)) {
throw new BaseApiException(ErrorCode.INVALID_TOKEN);
}
List<ArticleDTO> list = articleService.findDrafts(user.getIdUser());
PageInfo<ArticleDTO> pageInfo = new PageInfo<>(list);
return GlobalResultGenerator.genSuccessResult(pageInfo);
}
@GetMapping("/{idArticle}/share")
public GlobalResult<String> share(@PathVariable Integer idArticle) throws BaseApiException {
return GlobalResultGenerator.genResult(true, articleService.share(idArticle), "");
public GlobalResult<String> share(@PathVariable Integer idArticle){
User user = UserUtils.getCurrentUserByToken();
return GlobalResultGenerator.genResult(true, articleService.share(idArticle, user.getAccount()), "");
}
@PostMapping("/update-tags")
@AuthorshipInterceptor(moduleName = Module.ARTICLE_TAG)
public GlobalResult<Boolean> updateTags(@RequestBody Article article) throws BaseApiException, UnsupportedEncodingException {
public GlobalResult<Boolean> updateTags(@RequestBody Article article) throws UnsupportedEncodingException {
Long idArticle = article.getIdArticle();
String articleTags = article.getArticleTags();
User user = UserUtils.getCurrentUserByToken();
@ -106,7 +96,7 @@ public class ArticleController {
}
@PostMapping("/thumbs-up")
public GlobalResult<Integer> thumbsUp(@RequestBody ArticleThumbsUp articleThumbsUp) throws Exception {
public GlobalResult<Integer> thumbsUp(@RequestBody ArticleThumbsUp articleThumbsUp) {
if (Objects.isNull(articleThumbsUp) || Objects.isNull(articleThumbsUp.getIdArticle())) {
throw new BusinessException("数据异常,文章不存在!");
}
@ -116,13 +106,13 @@ public class ArticleController {
}
@PostMapping("/sponsor")
public GlobalResult sponsor(@RequestBody Sponsor sponsor) throws Exception {
public GlobalResult<Boolean> sponsor(@RequestBody Sponsor sponsor) {
if (Objects.isNull(sponsor) || Objects.isNull(sponsor.getDataId()) || Objects.isNull(sponsor.getDataType())) {
throw new IllegalArgumentException("数据异常");
}
User user = UserUtils.getCurrentUserByToken();
sponsor.setSponsor(user.getIdUser());
boolean flag = sponsorService.sponsorship(sponsor);
Boolean flag = sponsorService.sponsorship(sponsor);
return GlobalResultGenerator.genSuccessResult(flag);
}

View File

@ -4,13 +4,15 @@ import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.rymcu.forest.core.result.GlobalResult;
import com.rymcu.forest.core.result.GlobalResultGenerator;
import com.rymcu.forest.core.service.security.annotation.SecurityInterceptor;
import com.rymcu.forest.dto.BankAccountDTO;
import com.rymcu.forest.dto.TransactionRecordDTO;
import com.rymcu.forest.entity.User;
import com.rymcu.forest.service.BankAccountService;
import com.rymcu.forest.util.UserUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

View File

@ -5,7 +5,6 @@ import com.rymcu.forest.core.result.GlobalResultGenerator;
import com.rymcu.forest.entity.Comment;
import com.rymcu.forest.service.CommentService;
import com.rymcu.forest.util.UserUtils;
import com.rymcu.forest.web.api.exception.BaseApiException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@ -26,8 +25,8 @@ public class CommentController {
private CommentService commentService;
@PostMapping("/post")
public GlobalResult<Comment> postComment(@RequestBody Comment comment, HttpServletRequest request) throws BaseApiException {
comment.setCommentAuthorId(Objects.requireNonNull(UserUtils.getCurrentUserByToken()).getIdUser());
public GlobalResult<Comment> postComment(@RequestBody Comment comment, HttpServletRequest request) {
comment.setCommentAuthorId(UserUtils.getCurrentUserByToken().getIdUser());
comment = commentService.postComment(comment,request);
return GlobalResultGenerator.genSuccessResult(comment);
}

View File

@ -63,7 +63,7 @@ public class CommonApiController {
throw new ServiceException(GlobalResultMessage.SEND_FAIL.getMessage());
}
} else {
throw new UnknownAccountException("该邮箱未注册!");
throw new UnknownAccountException("未知账号");
}
return GlobalResultGenerator.genSuccessResult(GlobalResultMessage.SEND_SUCCESS.getMessage());
}

View File

@ -1,5 +1,6 @@
package com.rymcu.forest.web.api.common;
import com.alibaba.fastjson2.JSONObject;
import com.rymcu.forest.auth.JwtConstants;
import com.rymcu.forest.core.result.GlobalResult;
import com.rymcu.forest.core.result.GlobalResultGenerator;
@ -10,10 +11,9 @@ import com.rymcu.forest.util.FileUtils;
import com.rymcu.forest.util.SpringContextHolder;
import com.rymcu.forest.util.UserUtils;
import com.rymcu.forest.util.Utils;
import com.rymcu.forest.web.api.exception.BaseApiException;
import com.rymcu.forest.web.api.exception.ErrorCode;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.transaction.annotation.Transactional;
@ -117,12 +117,12 @@ public class UploadController {
@PostMapping("/file")
@Transactional(rollbackFor = Exception.class)
public GlobalResult uploadPicture(@RequestParam(value = "file", required = false) MultipartFile multipartFile, @RequestParam(defaultValue = "1") Integer type, HttpServletRequest request) throws IOException, BaseApiException {
public GlobalResult<JSONObject> uploadPicture(@RequestParam(value = "file", required = false) MultipartFile multipartFile, @RequestParam(defaultValue = "1") Integer type, HttpServletRequest request) throws IOException {
if (multipartFile == null) {
return GlobalResultGenerator.genErrorResult("请选择要上传的文件");
}
TokenUser tokenUser = getTokenUser(request);
Map data = new HashMap(2);
JSONObject data = new JSONObject(2);
if (multipartFile.getSize() == 0) {
data.put("message", "上传失败!");
@ -166,7 +166,7 @@ public class UploadController {
@PostMapping("/file/batch")
@Transactional(rollbackFor = Exception.class)
public GlobalResult batchFileUpload(@RequestParam(value = "file[]", required = false) MultipartFile[] multipartFiles, @RequestParam(defaultValue = "1") Integer type, HttpServletRequest request) throws BaseApiException {
public GlobalResult<JSONObject> batchFileUpload(@RequestParam(value = "file[]", required = false) MultipartFile[] multipartFiles, @RequestParam(defaultValue = "1") Integer type, HttpServletRequest request) {
TokenUser tokenUser = getTokenUser(request);
String typePath = getTypePath(type);
//图片存储路径
@ -210,46 +210,46 @@ public class UploadController {
}
Map data = new HashMap(2);
JSONObject data = new JSONObject(2);
data.put("errFiles", errFiles);
data.put("succMap", successMap);
return GlobalResultGenerator.genSuccessResult(data);
}
private TokenUser getTokenUser(HttpServletRequest request) throws BaseApiException {
private TokenUser getTokenUser(HttpServletRequest request) {
String authHeader = request.getHeader(JwtConstants.UPLOAD_TOKEN);
if (StringUtils.isBlank(authHeader)) {
throw new BaseApiException(ErrorCode.UNAUTHORIZED);
throw new UnauthorizedException();
}
return UserUtils.getTokenUser(authHeader);
}
@GetMapping("/simple/token")
public GlobalResult uploadSimpleToken(HttpServletRequest request) throws BaseApiException {
public GlobalResult<JSONObject> uploadSimpleToken(HttpServletRequest request) {
return getUploadToken(request, UPLOAD_SIMPLE_URL);
}
@GetMapping("/token")
public GlobalResult uploadToken(HttpServletRequest request) throws BaseApiException {
public GlobalResult<JSONObject> uploadToken(HttpServletRequest request) {
return getUploadToken(request, UPLOAD_URL);
}
private GlobalResult getUploadToken(HttpServletRequest request, String uploadUrl) throws BaseApiException {
private GlobalResult<JSONObject> getUploadToken(HttpServletRequest request, String uploadUrl) {
String authHeader = request.getHeader(JwtConstants.AUTHORIZATION);
if (StringUtils.isBlank(authHeader)) {
throw new BaseApiException(ErrorCode.UNAUTHORIZED);
throw new UnauthorizedException();
}
TokenUser tokenUser = UserUtils.getTokenUser(authHeader);
Map map = new HashMap(4);
map.put("uploadToken", tokenUser.getToken());
map.put("uploadURL", uploadUrl);
map.put("linkToImageURL", LINK_TO_IMAGE_URL);
return GlobalResultGenerator.genSuccessResult(map);
JSONObject jsonObject = new JSONObject();
jsonObject.put("uploadToken", tokenUser.getToken());
jsonObject.put("uploadURL", uploadUrl);
jsonObject.put("linkToImageURL", LINK_TO_IMAGE_URL);
return GlobalResultGenerator.genSuccessResult(jsonObject);
}
@PostMapping("/file/link")
@Transactional(rollbackFor = Exception.class)
public GlobalResult linkToImageUrl(@RequestBody LinkToImageUrlDTO linkToImageUrlDTO, HttpServletRequest request) throws IOException, BaseApiException {
public GlobalResult linkToImageUrl(@RequestBody LinkToImageUrlDTO linkToImageUrlDTO, HttpServletRequest request) throws IOException {
TokenUser tokenUser = getTokenUser(request);
String url = linkToImageUrlDTO.getUrl();

View File

@ -1,28 +0,0 @@
package com.rymcu.forest.web.api.exception;
/**
* 服务业务异常如 账号或密码错误 该异常只做INFO级别的日志记录 @see WebMvcConfigurer
* @author ronger
*/
public class BaseApiException extends Exception {
private int code;
private String message;
public BaseApiException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.code = errorCode.getCode();
this.message = errorCode.getMessage();
}
public int getCode() {
return code;
}
public String getExtraMessage() {
return message;
}
}

View File

@ -1,34 +0,0 @@
package com.rymcu.forest.web.api.exception;
import com.rymcu.forest.config.BaseExceptionHandler;
import com.rymcu.forest.core.result.GlobalResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ControllerAdvice(basePackages = {"com.rymcu.forest.web.api", "com.rymcu.forest.jwt"} )
public class BaseApiExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(BaseExceptionHandler.class);
@ExceptionHandler(BaseApiException.class)
@ResponseBody
public GlobalResult handlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
logger.error(ex.getMessage());
GlobalResult result = new GlobalResult();
if (ex instanceof BaseApiException) {
result.setCode(((BaseApiException) ex).getCode());
result.setMessage(ex.getMessage());
} /*else if (ex instanceof Exception) {
result.setCode(ErrorCode.INTERNAL_SERVER_ERROR.getCode());
result.setMessage("用户无权限");
}*/
result.setSuccess(false);
return result;
}
}

View File

@ -1,28 +0,0 @@
package com.rymcu.forest.web.api.exception;
public enum ErrorCode {
UNAUTHORIZED(401, "请求要求用户的身份认证"),
INVALID_TOKEN(402, "TOKEN验证失败无效的TOKEN"),
TOKEN_(402, "TOKEN验证失败无效的TOKEN"),
ACCESS_DENIED(403, "服务器拒绝请求!"),
NOT_FOUND(404, "此接口不存在"),
INTERNAL_SERVER_ERROR(500, "服务内部异常");
private int code;
private String message;
ErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}

View File

@ -3,8 +3,9 @@ package com.rymcu.forest.web.api.follow;
import com.rymcu.forest.core.result.GlobalResult;
import com.rymcu.forest.core.result.GlobalResultGenerator;
import com.rymcu.forest.entity.Follow;
import com.rymcu.forest.entity.User;
import com.rymcu.forest.service.FollowService;
import com.rymcu.forest.web.api.exception.BaseApiException;
import com.rymcu.forest.util.UserUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@ -20,19 +21,24 @@ public class FollowController {
private FollowService followService;
@GetMapping("/is-follow")
public GlobalResult isFollow(@RequestParam Integer followingId, @RequestParam String followingType) throws BaseApiException {
Boolean b = followService.isFollow(followingId, followingType);
public GlobalResult isFollow(@RequestParam Integer followingId, @RequestParam String followingType) {
User tokenUser = UserUtils.getCurrentUserByToken();
Boolean b = followService.isFollow(followingId, followingType, tokenUser.getIdUser());
return GlobalResultGenerator.genSuccessResult(b);
}
@PostMapping
public GlobalResult follow(@RequestBody Follow follow) throws BaseApiException {
Boolean b = followService.follow(follow);
public GlobalResult<Boolean> follow(@RequestBody Follow follow) {
User tokenUser = UserUtils.getCurrentUserByToken();
follow.setFollowerId(tokenUser.getIdUser());
Boolean b = followService.follow(follow, tokenUser.getNickname());
return GlobalResultGenerator.genSuccessResult(b);
}
@PostMapping("cancel-follow")
public GlobalResult cancelFollow(@RequestBody Follow follow) throws BaseApiException {
public GlobalResult cancelFollow(@RequestBody Follow follow) {
User tokenUser = UserUtils.getCurrentUserByToken();
follow.setFollowerId(tokenUser.getIdUser());
Boolean b = followService.cancelFollow(follow);
return GlobalResultGenerator.genSuccessResult(b);
}

View File

@ -9,13 +9,10 @@ import com.rymcu.forest.entity.Notification;
import com.rymcu.forest.entity.User;
import com.rymcu.forest.service.NotificationService;
import com.rymcu.forest.util.UserUtils;
import com.rymcu.forest.web.api.exception.BaseApiException;
import com.rymcu.forest.web.api.exception.ErrorCode;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
/**
* 消息通知
@ -29,32 +26,27 @@ public class NotificationController {
private NotificationService notificationService;
@GetMapping("/all")
public GlobalResult<PageInfo<NotificationDTO>> notifications(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows) throws BaseApiException {
public GlobalResult<PageInfo<NotificationDTO>> notifications(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows) {
User user = UserUtils.getCurrentUserByToken();
if (Objects.isNull(user)) {
throw new BaseApiException(ErrorCode.TOKEN_);
}
PageHelper.startPage(page, rows);
List<NotificationDTO> list = notificationService.findNotifications(user.getIdUser());
PageInfo<NotificationDTO> pageInfo = new PageInfo(list);
PageInfo<NotificationDTO> pageInfo = new PageInfo<>(list);
return GlobalResultGenerator.genSuccessResult(pageInfo);
}
@GetMapping("/unread")
public GlobalResult<PageInfo<Notification>> unreadNotification(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows) throws BaseApiException {
public GlobalResult<PageInfo<Notification>> unreadNotification(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows) {
User user = UserUtils.getCurrentUserByToken();
if (Objects.isNull(user)) {
throw new BaseApiException(ErrorCode.TOKEN_);
}
PageHelper.startPage(page, rows);
List<Notification> list = notificationService.findUnreadNotifications(user.getIdUser());
PageInfo<Notification> pageInfo = new PageInfo(list);
PageInfo<Notification> pageInfo = new PageInfo<>(list);
return GlobalResultGenerator.genSuccessResult(pageInfo);
}
@PutMapping("/read/{id}")
public GlobalResult read(@PathVariable Long id) {
Integer result = notificationService.readNotification(id);
User user = UserUtils.getCurrentUserByToken();
Integer result = notificationService.readNotification(id, user.getIdUser());
if (result == 0) {
return GlobalResultGenerator.genErrorResult("标记已读失败");
}
@ -62,7 +54,7 @@ public class NotificationController {
}
@PutMapping("/read-all")
public GlobalResult readAll() throws BaseApiException {
public GlobalResult readAll() {
Integer result = notificationService.readAllNotification();
if (result == 0) {
return GlobalResultGenerator.genErrorResult("标记已读失败");

View File

@ -13,7 +13,6 @@ import com.rymcu.forest.enumerate.Module;
import com.rymcu.forest.service.PortfolioService;
import com.rymcu.forest.service.UserService;
import com.rymcu.forest.util.UserUtils;
import com.rymcu.forest.web.api.exception.BaseApiException;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@ -39,7 +38,7 @@ public class PortfolioController {
}
@PostMapping("/post")
public GlobalResult<Portfolio> add(@RequestBody Portfolio portfolio) throws BaseApiException {
public GlobalResult<Portfolio> add(@RequestBody Portfolio portfolio) {
User user = UserUtils.getCurrentUserByToken();
portfolio.setPortfolioAuthorId(user.getIdUser());
portfolio = portfolioService.postPortfolio(portfolio);
@ -48,7 +47,7 @@ public class PortfolioController {
@PutMapping("/post")
@AuthorshipInterceptor(moduleName = Module.PORTFOLIO)
public GlobalResult<Portfolio> update(@RequestBody Portfolio portfolio) throws BaseApiException {
public GlobalResult<Portfolio> update(@RequestBody Portfolio portfolio) {
if (portfolio.getIdPortfolio() == null || portfolio.getIdPortfolio() == 0) {
throw new IllegalArgumentException("作品集主键参数异常!");
}
@ -60,7 +59,7 @@ public class PortfolioController {
@GetMapping("/{idPortfolio}/unbind-articles")
@AuthorshipInterceptor(moduleName = Module.PORTFOLIO)
public GlobalResult<PageInfo> unbindArticles(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows, @RequestParam(defaultValue = "") String searchText, @PathVariable Long idPortfolio) throws BaseApiException {
public GlobalResult<PageInfo> unbindArticles(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows, @RequestParam(defaultValue = "") String searchText, @PathVariable Long idPortfolio) {
if (idPortfolio == null || idPortfolio == 0) {
throw new IllegalArgumentException("作品集主键参数异常!");
}
@ -110,7 +109,7 @@ public class PortfolioController {
@DeleteMapping("/delete")
@AuthorshipInterceptor(moduleName = Module.PORTFOLIO)
public GlobalResult<Boolean> delete(Long idPortfolio) throws BaseApiException {
public GlobalResult<Boolean> delete(Long idPortfolio) {
if (idPortfolio == null || idPortfolio == 0) {
throw new IllegalArgumentException("参数异常!");
}

View File

@ -36,15 +36,15 @@ public class UserController {
@GetMapping("/{account}")
@VisitLogger
public GlobalResult detail(@PathVariable String account){
public GlobalResult detail(@PathVariable String account) {
UserDTO userDTO = userService.findUserDTOByAccount(account);
return GlobalResultGenerator.genSuccessResult(userDTO);
}
@GetMapping("/{account}/articles")
public GlobalResult<PageInfo<ArticleDTO>> userArticles(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account){
public GlobalResult<PageInfo<ArticleDTO>> userArticles(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account) {
UserDTO userDTO = userService.findUserDTOByAccount(account);
if (userDTO == null){
if (userDTO == null) {
return GlobalResultGenerator.genErrorResult("用户不存在!");
}
PageHelper.startPage(page, rows);
@ -54,9 +54,9 @@ public class UserController {
}
@GetMapping("/{account}/portfolios")
public GlobalResult<PageInfo<PortfolioDTO>> userPortfolios(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account){
public GlobalResult<PageInfo<PortfolioDTO>> userPortfolios(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account) {
UserDTO userDTO = userService.findUserDTOByAccount(account);
if (userDTO == null){
if (userDTO == null) {
return GlobalResultGenerator.genErrorResult("用户不存在!");
}
PageHelper.startPage(page, rows);
@ -66,9 +66,9 @@ public class UserController {
}
@GetMapping("/{account}/followers")
public GlobalResult<PageInfo<UserDTO>> userFollowers(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account){
public GlobalResult<PageInfo<UserDTO>> userFollowers(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account) {
UserDTO userDTO = userService.findUserDTOByAccount(account);
if (userDTO == null){
if (userDTO == null) {
return GlobalResultGenerator.genErrorResult("用户不存在!");
}
PageHelper.startPage(page, rows);
@ -78,9 +78,9 @@ public class UserController {
}
@GetMapping("/{account}/followings")
public GlobalResult<PageInfo<UserDTO>> userFollowings(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account){
public GlobalResult<PageInfo<UserDTO>> userFollowings(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account) {
UserDTO userDTO = userService.findUserDTOByAccount(account);
if (userDTO == null){
if (userDTO == null) {
return GlobalResultGenerator.genErrorResult("用户不存在!");
}
PageHelper.startPage(page, rows);

View File

@ -23,7 +23,7 @@
insert into forest_notification (id_user, data_type, data_id, data_summary, created_time) values (#{idUser}, #{dataType}, #{dataId}, #{dataSummary}, sysdate())
</insert>
<update id="readNotification">
update forest_notification set has_read = '1' where id = #{id}
update forest_notification set has_read = '1' where id = #{id} and id_user = #{idUser}
</update>
<update id="readAllNotification">
update forest_notification set has_read = '1' where id_user = #{idUser} and has_read = '0'

View File

@ -5,7 +5,6 @@ import com.rymcu.forest.dto.ArticleSearchDTO;
import com.rymcu.forest.dto.ArticleTagDTO;
import com.rymcu.forest.dto.Author;
import com.rymcu.forest.entity.User;
import com.rymcu.forest.web.api.exception.BaseApiException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
@ -94,11 +93,10 @@ class ArticleServiceTest {
*
* 测试数据是否会返回Article的Id并且Id会填充到测试数据中
* @throws UnsupportedEncodingException
* @throws BaseApiException
*/
@Test
@BeforeEach
public void postArticle() throws UnsupportedEncodingException, BaseApiException {
public void postArticle() throws UnsupportedEncodingException {
Long articleId = articleService.postArticle(testArticle, testUser);
testArticle.setIdArticle(articleId);
assertNotNull(articleId);
@ -218,10 +216,9 @@ class ArticleServiceTest {
* cn.hutool.core.io.IORuntimeException: Path [xxxxxxx] is not directory!
* 这是由于Lucene的路径通配符默认为linux的解决方式
* 将ArticleIndexUtil.deleteIndex()方法中的PATH改为WINDOW_PATH即可 :)
* @throws BaseApiException 基础Api错误
*/
@Test
void delete() throws BaseApiException {
void delete() {
articleService.delete(testArticle.getIdArticle());
ArticleDTO articleDTOByIdAfter = articleService.findArticleDTOById(testArticle.getIdArticle(), 0);
assertNull(articleDTOByIdAfter);