Feature/server java check style & p3c 框架相关改造 (#273)

* checkstyle P3C和相关框架优化

* checkstyle P3C和相关框架优化

---------

Co-authored-by: zdl <zdl@qq.com>
This commit is contained in:
oooooooo 2024-06-08 22:08:48 +08:00 committed by GitHub
parent 0cd3e312e7
commit 1125661c1f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 458 additions and 298 deletions

91
pom.xml
View File

@ -16,6 +16,7 @@
<packaging>pom</packaging>
<modules>
<module>survey-checkstyle</module>
<module>survey-server</module>
<module>survey-common</module>
<module>survey-dal</module>
@ -72,6 +73,16 @@
<artifactId>java-jwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${lang3.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
@ -123,6 +134,86 @@
</execution>
</executions>
</plugin>
<!-- PMD插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.16.0</version>
<configuration>
<verbose>true</verbose>
<!-- 规范的配置 -->
<rulesets>
<ruleset>rulesets/java/ali-concurrent.xml</ruleset>
<ruleset>rulesets/java/ali-constant.xml</ruleset>
<ruleset>rulesets/java/ali-exception.xml</ruleset>
<ruleset>rulesets/java/ali-flowcontrol.xml</ruleset>
<ruleset>rulesets/java/ali-naming.xml</ruleset>
<ruleset>rulesets/java/ali-oop.xml</ruleset>
<ruleset>rulesets/java/ali-orm.xml</ruleset>
<ruleset>rulesets/java/ali-other.xml</ruleset>
<ruleset>rulesets/java/ali-set.xml</ruleset>
</rulesets>
<printFailingErrors>true</printFailingErrors>
</configuration>
<executions>
<execution>
<id>pmd-check-verify</id>
<phase>package</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.alibaba.p3c</groupId>
<artifactId>p3c-pmd</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<configLocation>checkstyle-rule.xml</configLocation>
<encoding>UTF-8</encoding>
<logViolationsToConsole>true</logViolationsToConsole>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
</configuration>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.xiaojusurvey.engine</groupId>
<artifactId>survey-checkstyle</artifactId>
<version>base</version>
</dependency>
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>8.41.1</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<skip>false</skip>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>

25
survey-checkstyle/pom.xml Normal file
View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>survey-engine</artifactId>
<groupId>com.xiaojusurvey.engine</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>survey-checkstyle</artifactId>
<version>base</version>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,176 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
<!-- 检查文件是否以一个空行结束 -->
<module name="NewlineAtEndOfFile"/>
<!-- 文件长度不超过1500行 -->
<module name="FileLength">
<property name="max" value="1500"/>
</module>
<!-- 每个java文件一个语法树 -->
<module name="TreeWalker">
<!-- import检查-->
<!-- 检查是否从非法的包中导入了类 -->
<module name="IllegalImport"/>
<!-- 检查是否导入了多余的包 -->
<module name="RedundantImport"/>
<!-- 没用的import检查比如1.没有被用到2.重复的3.import java.lang的4.import 与该类在同一个package的 -->
<module name="UnusedImports"/>
<!-- 注释检查 -->
<!-- 检查构造函数的javadoc -->
<module name="JavadocType">
<property name="allowUnknownTags" value="true"/>
<message key="javadoc.missing" value="类注释缺少Javadoc注释。"/>
</module>
<!-- 命名检查 -->
<!-- 局部的final变量包括catch中的参数的检查 -->
<module name="LocalFinalVariableName"/>
<!-- 局部的非final型的变量包括catch中的参数的检查 -->
<module name="LocalVariableName"/>
<!-- 包名的检查(只允许小写字母),默认^[a-z]+(\.[a-zA-Z_][a-zA-Z_0-9_]*)*$ -->
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
<message key="name.invalidPattern" value="包名 ''{0}'' 要符合 ''{1}''格式."/>
</module>
<!-- 仅仅是static型的变量不包括static final型的检查 -->
<module name="StaticVariableName"/>
<!-- Class或Interface名检查默认^[A-Z][a-zA-Z0-9]*$-->
<module name="TypeName">
<property name="severity" value="warning"/>
<message key="name.invalidPattern" value="名称 ''{0}'' 要符合 ''{1}''格式."/>
</module>
<!-- 非static型变量的检查 -->
<module name="MemberName"/>
<!-- 方法名的检查 -->
<module name="MethodName"/>
<!-- 方法的参数名 -->
<module name="ParameterName "/>
<!-- 常量名的检查(只允许大写),默认^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$ -->
<module name="ConstantName"/>
<!-- 定义检查 -->
<!-- 检查数组类型定义的样式 -->
<module name="ArrayTypeStyle"/>
<!-- 检查long型定义是否有大写的“L” -->
<module name="UpperEll"/>
<!-- 方法不超过50行 -->
<module name="MethodLength">
<property name="tokens" value="METHOD_DEF"/>
<property name="max" value="50"/>
</module>
<!-- 方法的参数个数不超过5个。 并且不对构造方法进行检查-->
<module name="ParameterNumber">
<property name="max" value="5"/>
<property name="ignoreOverriddenMethods" value="true"/>
<property name="tokens" value="METHOD_DEF"/>
</module>
<!-- 空格检查-->
<!-- 方法名后跟左圆括号"(" -->
<module name="MethodParamPad"/>
<!-- 在类型转换时,不允许左圆括号右边有空格,也不允许与右圆括号左边有空格 -->
<module name="TypecastParenPad"/>
<!-- 检查在某个特定关键字之后应保留空格 -->
<module name="NoWhitespaceAfter"/>
<!-- 检查在某个特定关键字之前应保留空格 -->
<module name="NoWhitespaceBefore"/>
<!-- 操作符换行策略检查 -->
<module name="OperatorWrap"/>
<!-- 圆括号空白 -->
<module name="ParenPad"/>
<!-- 检查分隔符是否在空白之后 -->
<module name="WhitespaceAfter"/>
<!-- 检查分隔符周围是否有空白 -->
<module name="WhitespaceAround"/>
<!-- 修饰符检查 -->
<!-- 检查修饰符的顺序是否遵照java语言规范默认public、protected、private、abstract、static、final、transient、volatile、synchronized、native、strictfp -->
<module name="ModifierOrder"/>
<!-- 检查接口和annotation中是否有多余修饰符如接口方法不必使用public -->
<module name="RedundantModifier"/>
<!-- 代码块检查 -->
<!-- 检查是否有嵌套代码块 -->
<module name="AvoidNestedBlocks"/>
<!-- 检查是否有空代码块 -->
<module name="EmptyBlock"/>
<!-- 检查左大括号位置 -->
<module name="LeftCurly"/>
<!-- 检查代码块是否缺失{} -->
<module name="NeedBraces"/>
<!-- 检查右大括号位置 -->
<module name="RightCurly"/>
<!-- 代码检查 -->
<!-- 检查空的代码段 -->
<module name="EmptyStatement"/>
<!-- 检查在重写了equals方法后是否重写了hashCode方法 -->
<module name="EqualsHashCode"/>
<!-- 检查局部变量或参数是否隐藏了类中的变量 -->
<module name="HiddenField">
<property name="tokens" value="VARIABLE_DEF"/>
</module>
<!-- 检查子表达式中是否有赋值操作 -->
<module name="InnerAssignment"/>
<!-- 检查switch语句是否有default -->
<module name="MissingSwitchDefault"/>
<!-- 检查是否有过度复杂的布尔表达式 -->
<module name="SimplifyBooleanExpression"/>
<!-- 检查是否有过于复杂的布尔返回代码段 -->
<module name="SimplifyBooleanReturn"/>
<!-- 类设计检查 -->
<!-- 检查类是否为扩展设计l -->
<!-- 检查只有private构造函数的类是否声明为final -->
<module name="FinalClass"/>
<!-- 检查接口是否仅定义类型 -->
<module name="InterfaceIsType"/>
<!-- 检查类成员的可见度 检查类成员的可见性。只有static final 成员是public的
除非在本检查的protectedAllowed和packagedAllowed属性中进行了设置-->
<module name="VisibilityModifier">
<property name="packageAllowed" value="true"/>
<property name="protectedAllowed" value="true"/>
</module>
<!-- 语法 -->
<!-- String的比较不能用!= 和 == -->
<module name="StringLiteralEquality"/>
<!-- 限制for循环最多嵌套2层 -->
<module name="NestedForDepth">
<property name="max" value="2"/>
</module>
<!-- if最多嵌套3层 -->
<module name="NestedIfDepth">
<property name="max" value="3"/>
</module>
<!-- 检查未被注释的main方法,排除以Appllication结尾命名的类 -->
<module name="UncommentedMain">
<property name="excludedClasses" value=".*[Application,Test]$"/>
</module>
<!-- 禁止使用System.out.println -->
<module name="Regexp">
<property name="format" value="System\.out\.println"/>
<property name="illegalPattern" value="true"/>
</module>
<!-- return个数 3个-->
<module name="ReturnCount">
<property name="max" value="3"/>
</module>
<!--try catch 异常处理数量 3-->
<module name="NestedTryDepth ">
<property name="max" value="3"/>
</module>
<!-- clone方法必须调用了super.clone() -->
<module name="SuperClone"/>
<!-- finalize 必须调用了super.finalize() -->
<module name="SuperFinalize"/>
</module>
</module>

View File

@ -31,8 +31,6 @@
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- jwt-->
<dependency>
<groupId>com.auth0</groupId>

View File

@ -3,7 +3,6 @@ package com.xiaojusurvey.engine.common.entity;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
public class Status implements Serializable {

View File

@ -5,11 +5,9 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.data.mongodb.core.mapping.Document;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
/**
* @Author: LYF
@ -20,7 +18,7 @@ import java.util.ArrayList;
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Data
public class User extends BaseEntity{
public class User extends BaseEntity {
/**
* 用户名

View File

@ -14,15 +14,15 @@ public abstract class BaseException extends RuntimeException {
public BaseException(String errorMsg, Integer code) {
super(errorMsg);
this.code=code;
this.errorMsg=errorMsg;
this.message=errorMsg;
this.code = code;
this.errorMsg = errorMsg;
this.message = errorMsg;
}
public BaseException(String errorMsg, Integer code,Throwable t) {
super(errorMsg,t);
this.code=code;
this.errorMsg=errorMsg;
this.message=errorMsg;
public BaseException(String errorMsg, Integer code, Throwable t) {
super(errorMsg, t);
this.code = code;
this.errorMsg = errorMsg;
this.message = errorMsg;
}
}

View File

@ -1,6 +1,6 @@
package com.xiaojusurvey.engine.common.exception;
public class DaoException extends BaseException{
public class DaoException extends BaseException {
public DaoException(String errorMsg, Integer code) {
super(errorMsg, code);

View File

@ -1,8 +1,8 @@
package com.xiaojusurvey.engine.core.auth;
import com.xiaojusurvey.engine.common.entity.user.CaptchaVo;
import com.xiaojusurvey.engine.core.auth.domain.UserParam;
import com.xiaojusurvey.engine.core.auth.domain.UserVo;
import com.xiaojusurvey.engine.core.auth.vo.CaptchaVo;
import com.xiaojusurvey.engine.core.auth.param.UserParam;
import com.xiaojusurvey.engine.core.auth.vo.UserVo;
/**
* @Author: LYF

View File

@ -1,7 +1,7 @@
package com.xiaojusurvey.engine.core.auth.captcha;
import com.xiaojusurvey.engine.common.entity.user.Captcha;
import com.xiaojusurvey.engine.common.entity.user.CaptchaVo;
import com.xiaojusurvey.engine.core.auth.vo.CaptchaVo;
/**
* @Author: LYF
@ -11,6 +11,7 @@ import com.xiaojusurvey.engine.common.entity.user.CaptchaVo;
public interface CaptchaGenerator {
/**
* 根据文本生成SVG
*
* @param text
* @return
*/
@ -19,15 +20,16 @@ public interface CaptchaGenerator {
/**
* 生成验证码持久对象
*
* @param length
* @return
*/
Captcha generateRandomText(int length);
default CaptchaVo generateRandomSvg(Captcha captcha) {
if (captcha == null || captcha.getId() == null){
if (captcha == null || captcha.getId() == null) {
throw new IllegalArgumentException("captcha or id is null");
}else {
} else {
return new CaptchaVo(captcha.getId(), generateRandomSvg(captcha.getText()));
}
}

View File

@ -16,13 +16,16 @@ public class SimpleCaptchaGenerator implements CaptchaGenerator {
@Override
public String generateRandomSvg(String text) {
// 生成包含验证码的 SVG 数据
String svgData = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"150\" height=\"50\" viewBox=\"0,0,150,50\">" +
"<rect width=\"100%\" height=\"100%\" fill=\"#f0f0f0\"/>" +
"<text x=\"50%\" y=\"50%\" dominant-baseline=\"middle\" text-anchor=\"middle\" fill=\"#000\">" + text + "</text>" +
"</svg>";
String svgData = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"150\" height=\"50\" viewBox=\"0,0,150,50\">"
+ "<rect width=\"100%\" height=\"100%\" fill=\"#f0f0f0\"/>"
+ "<text x=\"50%\" y=\"50%\" dominant-baseline=\"middle\" text-anchor=\"middle\" fill=\"#000\">"
+ text
+ "</text>"
+ "</svg>";
return svgData;
}
@Override
public Captcha generateRandomText(int length) {
String chars = "123456789";

View File

@ -3,13 +3,13 @@ package com.xiaojusurvey.engine.core.auth.impl;
import com.xiaojusurvey.engine.common.constants.RespErrorCode;
import com.xiaojusurvey.engine.common.entity.token.Token;
import com.xiaojusurvey.engine.common.entity.user.Captcha;
import com.xiaojusurvey.engine.common.entity.user.CaptchaVo;
import com.xiaojusurvey.engine.core.auth.vo.CaptchaVo;
import com.xiaojusurvey.engine.common.entity.user.User;
import com.xiaojusurvey.engine.common.exception.ServiceException;
import com.xiaojusurvey.engine.core.auth.AuthService;
import com.xiaojusurvey.engine.core.auth.captcha.CaptchaGenerator;
import com.xiaojusurvey.engine.core.auth.domain.UserParam;
import com.xiaojusurvey.engine.core.auth.domain.UserVo;
import com.xiaojusurvey.engine.core.auth.param.UserParam;
import com.xiaojusurvey.engine.core.auth.vo.UserVo;
import com.xiaojusurvey.engine.core.auth.util.AuthUtil;
import com.xiaojusurvey.engine.core.auth.util.JwtTokenUtil;
import com.xiaojusurvey.engine.core.user.UserService;

View File

@ -1,4 +1,4 @@
package com.xiaojusurvey.engine.core.auth.domain;
package com.xiaojusurvey.engine.core.auth.param;
import com.xiaojusurvey.engine.common.entity.user.User;
import lombok.Data;

View File

@ -1,6 +1,5 @@
package com.xiaojusurvey.engine.core.auth.util;
import com.xiaojusurvey.engine.common.entity.user.User;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@ -14,9 +13,10 @@ public class AuthUtil {
/**
* 生成BCryptPasswordEncoder密码
*
* @return 加密字符串
*/
public static String encryptPassword(String password,String username) {
public static String encryptPassword(String password, String username) {
String inputWithSalt = password + username;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
@ -32,5 +32,4 @@ public class AuthUtil {
}
}

View File

@ -3,9 +3,7 @@ package com.xiaojusurvey.engine.core.auth.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.sun.javafx.binding.StringConstant;
import com.xiaojusurvey.engine.common.constants.RespErrorCode;
import com.xiaojusurvey.engine.common.entity.token.Token;
import com.xiaojusurvey.engine.common.entity.user.User;
@ -16,7 +14,6 @@ import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;
@ -36,21 +33,23 @@ public class JwtTokenUtil {
/**
* 认证头
*/
public static final String AUTHORIZATION_HEADER = "Authorization";
private static final String AUTHORIZATION_HEADER = "Authorization";
/**
* 空格
*/
public static final String SPACE = " ";
private static final String SPACE = " ";
/**
* 令牌前缀正则表达式
*/
public final static String BEARER_PATTERN = "^Bearer$";
private static final String BEARER_PATTERN = "^Bearer$";
private static final int LENGTH = 2;
/**
* 生成token
*
* @param user
* @return
*/
@ -64,11 +63,12 @@ public class JwtTokenUtil {
.withExpiresAt(expiryDate)
.withJWTId(UUID.randomUUID().toString())
.sign(Algorithm.HMAC256(secret));
return new Token(user.getUsername(), token,new Date(now.getTime() + expirationTime * HOUR_SECOND));
return new Token(user.getUsername(), token, new Date(now.getTime() + expirationTime * HOUR_SECOND));
}
/**
* 解密访问令牌
*
* @param tokenString 令牌
* @return 密钥内容
*/
@ -77,20 +77,19 @@ public class JwtTokenUtil {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)).build();
DecodedJWT jwt = verifier.verify(tokenString);
return jwt;
}catch (Exception e){
} catch (Exception e) {
throw new ServiceException(RespErrorCode.USER_NOT_EXISTS.getMessage(), RespErrorCode.USER_NOT_EXISTS.getCode());
}
}
public DecodedJWT getTokenStrByRequest(HttpServletRequest request) {
String header = request.getHeader(AUTHORIZATION_HEADER);
if (!StringUtils.hasText(header)) {
throw new ServiceException(RespErrorCode.USER_CREDENTIALS_ERROR.getMessage(), RespErrorCode.USER_CREDENTIALS_ERROR.getCode());
}
String[] splits = header.split(SPACE);
if (splits.length != 2) {
if (splits.length != LENGTH) {
throw new ServiceException(RespErrorCode.USER_CREDENTIALS_ERROR.getMessage(), RespErrorCode.USER_CREDENTIALS_ERROR.getCode());
}
if (!Pattern.matches(BEARER_PATTERN, splits[0])) {

View File

@ -1,4 +1,4 @@
package com.xiaojusurvey.engine.common.entity.user;
package com.xiaojusurvey.engine.core.auth.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -12,7 +12,7 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class CaptchaVo{
public class CaptchaVo {
private String id;

View File

@ -1,4 +1,4 @@
package com.xiaojusurvey.engine.core.auth.domain;
package com.xiaojusurvey.engine.core.auth.vo;
import lombok.Data;
@ -8,7 +8,7 @@ import lombok.Data;
* @Description: 用户vo
*/
@Data
public class UserVo{
public class UserVo {
private String token;
private String username;

View File

@ -27,6 +27,7 @@ public class UserServiceImpl implements UserService {
/**
* 查询用户
*
* @param username
* @param password
* @return
@ -38,7 +39,7 @@ public class UserServiceImpl implements UserService {
query.addCriteria(Criteria.where("username").is(username).and("password").is(encryptPassword));
//查询用户并返回
User user = mongoRepository.findOne(query, User.class);
if (ObjectUtils.isEmpty(user)){
if (ObjectUtils.isEmpty(user)) {
throw new ServiceException(RespErrorCode.USER_PASSWORD_ERROR.getMessage(), RespErrorCode.USER_PASSWORD_ERROR.getCode());
}
return user;

View File

@ -3,7 +3,7 @@ package com.xiaojusurvey.engine.repository.enums;
public enum ErrorEnum {
PARAM_NULL_ERROR("%s is null",1);
PARAM_NULL_ERROR("%s is null", 1);
private String errorMsg;

View File

@ -42,7 +42,7 @@ public class MongoRepositoryImpl implements MongoRepository {
@Override
public <T extends BaseEntity> T findOne(Query query, Class<T> entityClass) {
return mongoTemplate.findOne(query,entityClass);
return mongoTemplate.findOne(query, entityClass);
}
@Override

View File

@ -9,6 +9,7 @@ import org.springframework.stereotype.Component;
@Component
public class TestMessageProcessor implements MessageProcessor {
private static final int ORDER = 99;
@Override
public void before(Invocation invocation) {
@ -19,4 +20,9 @@ public class TestMessageProcessor implements MessageProcessor {
public Result after(Result result) {
return new Result();
}
@Override
public int getOrder() {
return ORDER;
}
}

View File

@ -5,4 +5,6 @@ public interface ExtensionProcessor {
void before(Invocation invocation);
Result after(Result result);
int getOrder();
}

View File

@ -1,33 +1,33 @@
package com.xiaojusurvey.engine.extensions.processor.aop;
import com.xiaojusurvey.engine.extensions.processor.Invocation;
import com.xiaojusurvey.engine.extensions.processor.Result;
import com.xiaojusurvey.engine.extensions.processor.annotation.Message;
import com.xiaojusurvey.engine.extensions.processor.annotation.Security;
import com.xiaojusurvey.engine.extensions.router.MessageProcessorRouter;
import com.xiaojusurvey.engine.extensions.router.SecurityProcessorRouter;
import com.xiaojusurvey.engine.extensions.router.BaseRouter;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Aspect
@Component
public class ExtensionAspect {
public class ExtensionAspect implements InitializingBean {
@Autowired
private MessageProcessorRouter messageProcessorRouter;
private List<BaseRouter> routerList;
private Map<Class, BaseRouter> routerMap = new LinkedHashMap<>();
@Autowired
private SecurityProcessorRouter securityProcessorRouter;
@Pointcut("@annotation(com.xiaojusurvey.engine.extensions.processor.annotation.Message) || @annotation(com.xiaojusurvey.engine.extensions.processor.annotation.Security)")
public void pointcut() {
@ -37,24 +37,25 @@ public class ExtensionAspect {
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
Message message = method.getAnnotation(Message.class);
Security security = method.getAnnotation(Security.class);
if (!Objects.isNull(message)) {
for (Map.Entry<Class, BaseRouter> routerEntry : routerMap.entrySet()) {
if (null != method.getAnnotation(routerEntry.getKey())) {
Invocation invocation = new Invocation(method.getName(), method.getParameterTypes(), pjp.getArgs());
messageProcessorRouter.before(invocation);
routerEntry.getValue().before(invocation);
}
if (!Objects.isNull(security)) {
Invocation invocation = new Invocation(method.getName(), method.getParameterTypes(), pjp.getArgs());
securityProcessorRouter.before(invocation);
}
Result result = new Result(pjp.proceed(pjp.getArgs()));
if (!Objects.isNull(message)) {
result = messageProcessorRouter.after(result);
for (Map.Entry<Class, BaseRouter> routerEntry : routerMap.entrySet()) {
if (null != method.getAnnotation(routerEntry.getKey())) {
result = routerEntry.getValue().after(result);
}
if (!Objects.isNull(security)) {
result = securityProcessorRouter.after(result);
}
return result.getValue();
}
@Override
public void afterPropertiesSet() throws Exception {
if (!CollectionUtils.isEmpty(routerList)) {
routerList.forEach(e -> routerMap.put(e.annotationClass(), e));
}
}
}

View File

@ -1,18 +1,48 @@
package com.xiaojusurvey.engine.extensions.router;
import com.xiaojusurvey.engine.extensions.processor.ExtensionProcessor;
import com.xiaojusurvey.engine.extensions.processor.Invocation;
import com.xiaojusurvey.engine.extensions.processor.Result;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.CollectionUtils;
public abstract class BaseRouter implements ApplicationContextAware {
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
public abstract class BaseRouter<T extends ExtensionProcessor> implements ApplicationContextAware, InitializingBean {
protected ApplicationContext applicationContext;
public abstract void before(Invocation invocation);
protected List<T> extensionProcessors = new ArrayList<>();
public abstract Result after(Result result);
public void before(Invocation invocation) {
for (T extensionProcessor : extensionProcessors) {
extensionProcessor.before(invocation);
}
}
public Result after(Result result) {
for (T extensionProcessor : extensionProcessors) {
result = extensionProcessor.after(result);
}
return result;
}
public abstract Class<?> annotationClass();
protected void initExtensionProcessors(Class<T> clazz) {
Map<String, T> messageProcessorMap = applicationContext.getBeansOfType(clazz);
if (!CollectionUtils.isEmpty(messageProcessorMap)) {
messageProcessorMap.entrySet().stream().forEach(e -> extensionProcessors.add(e.getValue()));
extensionProcessors.sort(Comparator.comparing(ExtensionProcessor::getOrder));
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

View File

@ -1,42 +1,21 @@
package com.xiaojusurvey.engine.extensions.router;
import com.xiaojusurvey.engine.extensions.message.MessageProcessor;
import com.xiaojusurvey.engine.extensions.processor.Invocation;
import com.xiaojusurvey.engine.extensions.processor.Result;
import org.springframework.beans.factory.InitializingBean;
import com.xiaojusurvey.engine.extensions.processor.annotation.Message;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Component
public class MessageProcessorRouter extends BaseRouter implements InitializingBean {
private List<MessageProcessor> messageProcessorList = new ArrayList<>();
@Order(0)
public class MessageProcessorRouter extends BaseRouter<MessageProcessor> {
@Override
public void afterPropertiesSet() throws Exception {
Map<String, MessageProcessor> messageProcessorMap = applicationContext.getBeansOfType(MessageProcessor.class);
if (!CollectionUtils.isEmpty(messageProcessorMap)) {
messageProcessorMap.entrySet().stream().forEach(e -> messageProcessorList.add(e.getValue()));
}
initExtensionProcessors(MessageProcessor.class);
}
@Override
public void before(Invocation invocation) {
for (MessageProcessor messageProcessor : messageProcessorList) {
messageProcessor.before(invocation);
}
}
@Override
public Result after(Result result) {
for (MessageProcessor messageProcessor : messageProcessorList) {
result = messageProcessor.after(result);
}
return result;
public Class<?> annotationClass() {
return Message.class;
}
}

View File

@ -1,41 +1,21 @@
package com.xiaojusurvey.engine.extensions.router;
import com.xiaojusurvey.engine.extensions.processor.Invocation;
import com.xiaojusurvey.engine.extensions.processor.Result;
import com.xiaojusurvey.engine.extensions.processor.annotation.Security;
import com.xiaojusurvey.engine.extensions.security.SecurityProcessor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Component
public class SecurityProcessorRouter extends BaseRouter implements InitializingBean {
private List<SecurityProcessor> securityProcessorList = new ArrayList<>();
@Order(1)
public class SecurityProcessorRouter extends BaseRouter<SecurityProcessor> {
@Override
public void afterPropertiesSet() throws Exception {
Map<String, SecurityProcessor> messageProcessorMap = applicationContext.getBeansOfType(SecurityProcessor.class);
if (!CollectionUtils.isEmpty(messageProcessorMap)) {
messageProcessorMap.entrySet().stream().forEach(e -> securityProcessorList.add(e.getValue()));
}
initExtensionProcessors(SecurityProcessor.class);
}
@Override
public void before(Invocation invocation) {
for (SecurityProcessor securityProcessor : securityProcessorList) {
securityProcessor.before(invocation);
}
}
@Override
public Result after(Result result) {
for (SecurityProcessor securityProcessor : securityProcessorList) {
result= securityProcessor.after(result);
}
return result;
public Class<?> annotationClass() {
return Security.class;
}
}

View File

@ -8,6 +8,7 @@ import org.springframework.stereotype.Component;
@Component
public class TestSecurityProcessor implements SecurityProcessor {
private static final int ORDER = 100;
@Override
public void before(Invocation invocation) {
@ -18,4 +19,9 @@ public class TestSecurityProcessor implements SecurityProcessor {
public Result after(Result result) {
return new Result();
}
@Override
public int getOrder() {
return ORDER;
}
}

View File

@ -35,21 +35,16 @@
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${lang3.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@ -11,20 +11,21 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 全局异常处理器
*
* @Author: LYF
* @CreateTime: 2024-06-05
* @Description: 全局异常处理器
*/
@RestControllerAdvice
public class ValidatedExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(ValidatedExceptionHandler.class);
private static final Logger LOG = LoggerFactory.getLogger(ValidatedExceptionHandler.class);
/**
* 自定义验证异常
*/
@ExceptionHandler(BindException.class)
public RpcResult handleBindException(BindException e) {
log.error(e.getMessage(), e);
LOG.error(e.getMessage(), e);
String message = e.getAllErrors().get(0).getDefaultMessage();
return RpcResultUtil.createFailedResult(RespErrorCode.PARAMETER_ERROR.getCode(), message);
}

View File

@ -1,8 +1,8 @@
package com.xiaojusurvey.engine.controller;
import com.xiaojusurvey.engine.common.entity.user.CaptchaVo;
import com.xiaojusurvey.engine.core.auth.domain.UserParam;
import com.xiaojusurvey.engine.core.auth.domain.UserVo;
import com.xiaojusurvey.engine.core.auth.vo.CaptchaVo;
import com.xiaojusurvey.engine.core.auth.param.UserParam;
import com.xiaojusurvey.engine.core.auth.vo.UserVo;
import com.xiaojusurvey.engine.common.rpc.RpcResult;
import com.xiaojusurvey.engine.common.util.RpcResultUtil;
import com.xiaojusurvey.engine.core.auth.AuthService;

View File

@ -1,138 +0,0 @@
package com.xiaojusurvey.engine.interceptor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Objects;
import java.util.UUID;
@Component
public class LogFilter extends OncePerRequestFilter {
private final Logger logger = LoggerFactory.getLogger(getClass());
public static final String TRACE_ID = "traceId";
public static final int SLOW_TIME_MILLIS = 5000;
public static final int LOG_MAX_LENGTH = 1024;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String url = null;
//计时器
StopWatch watch = null;
try {
// 获取url
url = getCompleteUrl(request);
// 设置traceId
String traceId = request.getHeader(TRACE_ID);
if (StringUtils.isBlank(traceId)) {
traceId = UUID.randomUUID().toString();
}
MDC.put(TRACE_ID, traceId);
request = new ContentCachingRequestWrapper(request);
response = new ContentCachingResponseWrapper(response);
watch = new StopWatch();
watch.start();
logger.info("Start request, ip:{} host:{} url:{} body:{}", getRemoteIP(request),
request.getRemoteHost(), url, getRequestBody(request));
filterChain.doFilter(request, response);
} finally {
if (watch != null) {
watch.stop();
if (watch.getTotalTimeMillis() > SLOW_TIME_MILLIS && !url.endsWith(".js")) {
logger.error("End slow request, ip:{} host:{} url:{} cost:{} ms resp:{}", getRemoteIP(request),
request.getRemoteHost(), url, watch.getTotalTimeMillis(), getResponseBody(response));
} else {
logger.info("End request, ip:{} host:{} url:{} cost:{} ms resp:{}", getRemoteIP(request),
request.getRemoteHost(), url, watch.getTotalTimeMillis(), getResponseBody(response));
}
}
MDC.clear();
updateResponse(response);
}
}
private String getRequestBody(HttpServletRequest request) {
ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
if (wrapper == null) {
return "";
}
return getBody(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding());
}
/**获取body 避免过长
*
* @param contentAsByteArray 请求体或响应体
* @param characterEncoding 字符集
* @return
*/
private String getBody(byte[] contentAsByteArray, String characterEncoding) {
if (contentAsByteArray == null) return null;
String body = "";
try {
body = new String(contentAsByteArray, characterEncoding);
// 最多打印1024字符
if (body.length() > LOG_MAX_LENGTH) {
body = body.substring(0, LOG_MAX_LENGTH) + "...";
}
} catch (Exception e) {
//
}
return body;
}
private String getResponseBody(HttpServletResponse response) {
ContentCachingResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
if (responseWrapper == null) {
return "";
}
return getBody(responseWrapper.getContentAsByteArray(), "UTF-8");
}
private void updateResponse(HttpServletResponse response) throws IOException {
ContentCachingResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
Objects.requireNonNull(responseWrapper).copyBodyToResponse();
}
private String getCompleteUrl(HttpServletRequest request) {
String url = request.getRequestURL().toString();
String queryString = "";
if (StringUtils.isNotEmpty(request.getQueryString())) {
try {
queryString = URLDecoder.decode(request.getQueryString(), "UTF-8");
} catch (UnsupportedEncodingException e) {
logger.error("URLDecoder.decode error:" + e.getMessage(), e);
}
url = url + "?" + queryString;
}
return url;
}
private String getRemoteIP(HttpServletRequest request) {
if (request.getHeader("x-forwarded-for") == null) {
return request.getRemoteAddr();
}
return request.getHeader("x-forwarded-for");
}
}

View File

@ -8,9 +8,8 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class SurveyWebMvcConfigurer implements WebMvcConfigurer {
@Bean
public LoginInterceptor loginInterceptor(){
public LoginInterceptor loginInterceptor() {
return new LoginInterceptor();
}

View File

@ -1,4 +1,11 @@
server.port=8080
spring.data.mongodb.uri=
spring.data.mongodb.database=
#spring.data.mongodb.database=
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=testdb
XIAOJU_SURVEY_JWT_EXPIRES_IN=8
XIAOJU_SURVEY_JWT_SECRET=xiaojuSurveyJwtSecret

View File

@ -2,3 +2,6 @@ server.port=8080
spring.data.mongodb.uri=
spring.data.mongodb.database=
XIAOJU_SURVEY_JWT_EXPIRES_IN=8
XIAOJU_SURVEY_JWT_SECRET=xiaojuSurveyJwtSecret

View File

@ -1 +1,7 @@
server.port=8080
spring.data.mongodb.uri=
spring.data.mongodb.database=
XIAOJU_SURVEY_JWT_EXPIRES_IN=8
XIAOJU_SURVEY_JWT_SECRET=xiaojuSurveyJwtSecret

View File

@ -1,6 +1 @@
spring.profiles.active=@spring.profiles.active@
#??
XIAOJU_SURVEY_JWT_EXPIRES_IN=8
XIAOJU_SURVEY_JWT_SECRET=xiaojuSurveyJwtSecret

View File

@ -1,10 +1,10 @@
package com.xiaojusurvey.engine.controller;
import com.xiaojusurvey.engine.SurveyApplication;
import com.xiaojusurvey.engine.common.entity.user.CaptchaVo;
import com.xiaojusurvey.engine.core.auth.vo.CaptchaVo;
import com.xiaojusurvey.engine.common.rpc.RpcResult;
import com.xiaojusurvey.engine.core.auth.domain.UserParam;
import com.xiaojusurvey.engine.core.auth.domain.UserVo;
import com.xiaojusurvey.engine.core.auth.param.UserParam;
import com.xiaojusurvey.engine.core.auth.vo.UserVo;
import com.xiaojusurvey.engine.core.auth.util.JwtTokenUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -23,8 +23,6 @@ public class AuthTest {
@Resource
private JwtTokenUtil jwtTokenUtil;
@Resource
AuthController authController;
@ -59,5 +57,4 @@ public class AuthTest {
}
}