[Feature]:Java共建 [用户] 模块 (#270)

1:新增返回错误参数
2:修改extensions模块POM导致不能打包
3:新增统一参数验证
4:新增IdResult类为了统一返回
This commit is contained in:
lyf 2024-06-07 14:23:37 +08:00 committed by GitHub
parent b5622f1199
commit f39cea0372
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
39 changed files with 1013 additions and 30 deletions

View File

@ -30,6 +30,7 @@
<java.compiler.target.version>1.8</java.compiler.target.version>
<lombok.version>1.18.8</lombok.version>
<junit.version>4.12</junit.version>
<jwt.version>4.4.0</jwt.version>
</properties>
<dependencyManagement>
@ -64,6 +65,11 @@
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${jwt.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@ -25,6 +25,20 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!--验证pom-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- jwt-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,41 @@
package com.xiaojusurvey.engine.common.constants;
import lombok.Getter;
@Getter
public enum RespErrorCode {
AUTHENTICATION_FAILED(1001, "没有权限"),
PARAMETER_ERROR(1002, "参数有误"),
USER_EXISTS(2001, "用户已存在"),
USER_NOT_EXISTS(2002, "用户不存在"),
USER_PASSWORD_ERROR(2003, "用户名或密码错误"),
USER_CREDENTIALS_ERROR(2004, "用户凭证错误"),
NO_SURVEY_PERMISSION(3001, "没有问卷权限"),
SURVEY_STATUS_TRANSFORM_ERROR(3002, "问卷状态转换报错"),
SURVEY_TYPE_ERROR(3003, "问卷类型错误"),
SURVEY_NOT_FOUND(3004, "问卷不存在"),
SURVEY_CONTENT_NOT_ALLOW(3005, "存在禁用内容"),
CAPTCHA_INCORRECT(4001, "验证码不正确"),
RESPONSE_SIGN_ERROR(9001, "签名不正确"),
RESPONSE_CURRENT_TIME_NOT_ALLOW(9002, "当前时间不允许提交"),
RESPONSE_OVER_LIMIT(9003, "超出限制"),
RESPONSE_SCHEMA_REMOVED(9004, "问卷已删除"),
RESPONSE_DATA_DECRYPT_ERROR(9005, "问卷已删除"),
UPLOAD_FILE_ERROR(5001, "上传文件错误");
private final int code;
private final String message;
RespErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}

View File

@ -1,15 +0,0 @@
package com.xiaojusurvey.engine.common.entity;
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
@Document("user")
@Data
public class User extends BaseEntity{
private String password;
private String username;
}

View File

@ -0,0 +1,47 @@
package com.xiaojusurvey.engine.common.entity.survey;
import com.xiaojusurvey.engine.common.entity.BaseEntity;
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;
/**
* @Author: LYF
* @CreateTime: 2024-06-05
* @Description: 问卷Survey
*/
@Document("surveyMeta")
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Data
public class SurveyMeta extends BaseEntity {
/**
* 问卷类型
*/
@NotBlank(message = "问卷类型不能为空")
@NotNull(message = "问卷类型不能为空")
private String surveyType;
/**
* 问卷标题
*/
private String title;
/**
* 问卷描述
*/
private String remark;
/**
* 创建方式
*/
private String createMethod;
/**
* 创建来源
*/
private String createFrom;
}

View File

@ -0,0 +1,29 @@
package com.xiaojusurvey.engine.common.entity.token;
import com.xiaojusurvey.engine.common.entity.BaseEntity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
/**
* @Author: LYF
* @CreateTime: 2024-06-06
* @Description: token
*/
@Document("token")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Token extends BaseEntity {
private String username;
private String token;
/**
* 过期时间
*/
private Date expirationTime;
}

View File

@ -0,0 +1,21 @@
package com.xiaojusurvey.engine.common.entity.user;
import com.xiaojusurvey.engine.common.entity.BaseEntity;
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
/**
* @Author: LYF
* @CreateTime: 2024-06-06
* @Description:
*/
@Document("captcha")
@Data
public class Captcha extends BaseEntity {
/**
* 验证码
*/
private String text;
}

View File

@ -0,0 +1,24 @@
package com.xiaojusurvey.engine.common.entity.user;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author: LYF
* @CreateTime: 2024-06-06
* @Description:
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
public class CaptchaVo{
private String id;
/**
* 验证码
*/
private String img;
}

View File

@ -0,0 +1,41 @@
package com.xiaojusurvey.engine.common.entity.user;
import com.xiaojusurvey.engine.common.entity.BaseEntity;
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
* @CreateTime: 2024-06-06
* @Description: 用户信息
*/
@Document("user")
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Data
public class User extends BaseEntity{
/**
* 用户名
*/
@NotBlank(message = "用户名不能为空")
@NotNull(message = "用户名不能为空")
private String username;
/**
* 密码
*/
@NotBlank(message = "密码不能为空")
@NotNull(message = "密码不能为空")
private String password;
}

View File

@ -10,15 +10,19 @@ public abstract class BaseException extends RuntimeException {
private Integer code;
private String message;
public BaseException(String errorMsg, Integer code) {
super(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;
}
}

View File

@ -45,4 +45,6 @@ public class RpcResultUtil {
result.setSuccess(Boolean.FALSE);
return result;
}
}

View File

@ -29,6 +29,10 @@
<groupId>com.xiaojusurvey.engine</groupId>
<artifactId>survey-extensions</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

View File

@ -0,0 +1,18 @@
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;
/**
* @Author: LYF
* @CreateTime: 2024-06-05
* @Description: AuthService
*/
public interface AuthService {
CaptchaVo captcha();
UserVo register(UserParam userParam);
UserVo login(UserParam userParam);
}

View File

@ -0,0 +1,34 @@
package com.xiaojusurvey.engine.core.auth.captcha;
import com.xiaojusurvey.engine.common.entity.user.Captcha;
import com.xiaojusurvey.engine.common.entity.user.CaptchaVo;
/**
* @Author: LYF
* @CreateTime: 2024-06-06
* @Description: 验证码生成顶级接口
*/
public interface CaptchaGenerator {
/**
* 根据文本生成SVG
* @param text
* @return
*/
String generateRandomSvg(String text);
/**
* 生成验证码持久对象
* @param length
* @return
*/
Captcha generateRandomText(int length);
default CaptchaVo generateRandomSvg(Captcha captcha) {
if (captcha == null || captcha.getId() == null){
throw new IllegalArgumentException("captcha or id is null");
}else {
return new CaptchaVo(captcha.getId(), generateRandomSvg(captcha.getText()));
}
}
}

View File

@ -0,0 +1,42 @@
package com.xiaojusurvey.engine.core.auth.captcha;
import com.xiaojusurvey.engine.common.entity.user.Captcha;
import org.springframework.stereotype.Service;
import java.util.Random;
/**
* @Author: LYF
* @CreateTime: 2024-06-06
* @Description: 简单验证码生成工具类
*/
@Service("simpleCaptchaGenerator")
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>";
return svgData;
}
@Override
public Captcha generateRandomText(int length) {
String chars = "123456789";
StringBuilder text = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++) {
int index = random.nextInt(chars.length());
text.append(chars.charAt(index));
}
Captcha captcha = new Captcha();
captcha.setText(text.toString());
return captcha;
}
}

View File

@ -0,0 +1,33 @@
package com.xiaojusurvey.engine.core.auth.domain;
import com.xiaojusurvey.engine.common.entity.user.User;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @Author: LYF
* @CreateTime: 2024-06-06
* @Description: 包含验证码的user对象
*/
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Data
public class UserParam extends User {
/**
* 验证码ID
*/
@NotBlank(message = "验证码不能为空")
@NotNull(message = "验证码不能为空")
private String captchaId;
/**
* 验证码信息
*/
@NotBlank(message = "验证码不能为空")
@NotNull(message = "验证码不能为空")
private String captcha;
}

View File

@ -0,0 +1,16 @@
package com.xiaojusurvey.engine.core.auth.domain;
import lombok.Data;
/**
* @Author: LYF
* @CreateTime: 2024-06-06
* @Description: 用户vo
*/
@Data
public class UserVo{
private String token;
private String username;
}

View File

@ -0,0 +1,119 @@
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.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.util.AuthUtil;
import com.xiaojusurvey.engine.core.auth.util.JwtTokenUtil;
import com.xiaojusurvey.engine.core.user.UserService;
import com.xiaojusurvey.engine.repository.MongoRepository;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
/**
* @Author: LYF
* @CreateTime: 2024-06-05
* @Description: 登录注册相关
*/
@Service("authService")
public class AuthServiceImpl implements AuthService {
@Resource
private MongoRepository mongoRepository;
@Resource(name = "simpleCaptchaGenerator")
private CaptchaGenerator captchaGenerator;
@Resource
private JwtTokenUtil jwtTokenUtil;
@Resource
private UserService userService;
@Override
public CaptchaVo captcha() {
Captcha captcha = captchaGenerator.generateRandomText(4);
mongoRepository.save(captcha);
return captchaGenerator.generateRandomSvg(captcha);
}
@Override
public UserVo register(UserParam userParam) {
checkCaptchaIsCorrect(userParam.getCaptchaId(), userParam.getCaptcha());
//查询用户名是否存在
Query query = new Query();
query.addCriteria(Criteria.where("username").is(userParam.getUsername()));
if (!ObjectUtils.isEmpty(mongoRepository.findOne(query, User.class))) {
throw new ServiceException(RespErrorCode.USER_EXISTS.getMessage(), RespErrorCode.USER_EXISTS.getCode());
}
//保存
User user = new User();
user.setUsername(userParam.getUsername());
user.setPassword(AuthUtil.encryptPassword(userParam.getPassword(), userParam.getUsername()));
mongoRepository.save(user);
return createTokenAndDeleteCaptcha(userParam);
}
/**
* 生成token,并删除验证码
*
* @param userParam
* @return
*/
private UserVo createTokenAndDeleteCaptcha(UserParam userParam) {
//生成token
Token token = jwtTokenUtil.generateToken(userParam);
// 验证过的验证码要删掉防止被别人保存重复调用
mongoRepository.deleteById(userParam.getCaptchaId(), Captcha.class);
UserVo userVo = new UserVo();
userVo.setToken(token.getToken());
userVo.setUsername(userParam.getUsername());
return userVo;
}
@Override
public UserVo login(UserParam userParam) {
//验证码
checkCaptchaIsCorrect(userParam.getCaptchaId(), userParam.getCaptcha());
//用户验证
userService.loadUserByUsernameAndPassword(userParam.getUsername(), userParam.getPassword());
//生成token
return createTokenAndDeleteCaptcha(userParam);
}
/**
* 判断验证码是否正确
*
* @param captchaId 验证码id
* @param captchaText 需要验证的文本
* @return
*/
public void checkCaptchaIsCorrect(String captchaId, String captchaText) {
if (ObjectUtils.isEmpty(captchaId) || ObjectUtils.isEmpty(captchaText)) {
throw new ServiceException(RespErrorCode.CAPTCHA_INCORRECT.getMessage(), RespErrorCode.CAPTCHA_INCORRECT.getCode());
}
Captcha captcha = mongoRepository.findById(captchaId, Captcha.class);
//非空判断
if (ObjectUtils.isEmpty(captcha)) {
throw new ServiceException(RespErrorCode.CAPTCHA_INCORRECT.getMessage(), RespErrorCode.CAPTCHA_INCORRECT.getCode());
}
if (!captchaText.equals(captcha.getText())) {
throw new ServiceException(RespErrorCode.CAPTCHA_INCORRECT.getMessage(), RespErrorCode.CAPTCHA_INCORRECT.getCode());
}
}
}

View File

@ -0,0 +1,36 @@
package com.xiaojusurvey.engine.core.auth.util;
import com.xiaojusurvey.engine.common.entity.user.User;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* @Author: LYF
* @CreateTime: 2024-06-05
* @Description: 安全相关工具类
*/
public class AuthUtil {
/**
* 生成BCryptPasswordEncoder密码
* @return 加密字符串
*/
public static String encryptPassword(String password,String username) {
String inputWithSalt = password + username;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hashBytes = md.digest(inputWithSalt.getBytes());
StringBuilder sb = new StringBuilder();
for (byte b : hashBytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("");
}
}
}

View File

@ -0,0 +1,103 @@
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;
import com.xiaojusurvey.engine.common.exception.ServiceException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
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;
@Component
public class JwtTokenUtil {
@Value("${XIAOJU_SURVEY_JWT_EXPIRES_IN}")
private long expirationTime;
@Value("${XIAOJU_SURVEY_JWT_SECRET}")
private String secret;
private static final long HOUR_MILLISECOND = 60 * 60 * 1000;
private static final long HOUR_SECOND = 60 * 60 * 1000;
/**
* 认证头
*/
public static final String AUTHORIZATION_HEADER = "Authorization";
/**
* 空格
*/
public static final String SPACE = " ";
/**
* 令牌前缀正则表达式
*/
public final static String BEARER_PATTERN = "^Bearer$";
/**
* 生成token
* @param user
* @return
*/
public Token generateToken(User user) {
//注意这里的是明文密码
Date now = new Date();
Date expiryDate = new Date(now.getTime() + expirationTime * HOUR_MILLISECOND);
String token = JWT.create()
.withClaim("username", user.getUsername())
.withClaim("password", user.getPassword())
.withExpiresAt(expiryDate)
.withJWTId(UUID.randomUUID().toString())
.sign(Algorithm.HMAC256(secret));
return new Token(user.getUsername(), token,new Date(now.getTime() + expirationTime * HOUR_SECOND));
}
/**
* 解密访问令牌
* @param tokenString 令牌
* @return 密钥内容
*/
public DecodedJWT decodeToken(String tokenString) {
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)).build();
DecodedJWT jwt = verifier.verify(tokenString);
return jwt;
}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) {
throw new ServiceException(RespErrorCode.USER_CREDENTIALS_ERROR.getMessage(), RespErrorCode.USER_CREDENTIALS_ERROR.getCode());
}
if (!Pattern.matches(BEARER_PATTERN, splits[0])) {
throw new ServiceException(RespErrorCode.USER_CREDENTIALS_ERROR.getMessage(), RespErrorCode.USER_CREDENTIALS_ERROR.getCode());
}
String tokenString = splits[1];
//解析
return decodeToken(tokenString);
}
}

View File

@ -0,0 +1,11 @@
package com.xiaojusurvey.engine.core.reslut;
import lombok.Data;
import java.io.Serializable;
@Data
public class IdResult implements Serializable {
private String id;
}

View File

@ -0,0 +1,13 @@
package com.xiaojusurvey.engine.core.survey;
import com.xiaojusurvey.engine.common.entity.survey.SurveyMeta;
import com.xiaojusurvey.engine.core.reslut.IdResult;
/**
* @Author: LYF
* @CreateTime: 2024-06-05
* @Description: 问卷Service
*/
public interface SurveyService {
IdResult createSurvey(SurveyMeta surveyMeta);
}

View File

@ -0,0 +1,30 @@
package com.xiaojusurvey.engine.core.survey.impl;
import com.xiaojusurvey.engine.common.entity.survey.SurveyMeta;
import com.xiaojusurvey.engine.core.reslut.IdResult;
import com.xiaojusurvey.engine.core.survey.SurveyService;
import com.xiaojusurvey.engine.repository.MongoRepository;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @Author: LYF
* @CreateTime: 2024-06-05
* @Description: 问卷ServiceImpl
*/
@Service("surveyService")
public class SurveyServiceImpl implements SurveyService {
@Resource
private MongoRepository mongoRepository;
/**
* 创建问卷
*/
@Override
public IdResult createSurvey(SurveyMeta surveyMeta) {
IdResult idResult = new IdResult();
idResult.setId(mongoRepository.save(surveyMeta).getId());
return idResult;
}
}

View File

@ -1,10 +1,12 @@
package com.xiaojusurvey.engine.core.user;
import com.xiaojusurvey.engine.common.entity.User;
import com.xiaojusurvey.engine.common.entity.user.User;
import java.util.List;
public interface UserService {
List<User> findAllUser();
User loadUserByUsernameAndPassword(String username, String password);
}

View File

@ -1,9 +1,15 @@
package com.xiaojusurvey.engine.core.user.impl;
import com.xiaojusurvey.engine.common.entity.User;
import com.xiaojusurvey.engine.common.constants.RespErrorCode;
import com.xiaojusurvey.engine.common.entity.user.User;
import com.xiaojusurvey.engine.common.exception.ServiceException;
import com.xiaojusurvey.engine.core.auth.util.AuthUtil;
import com.xiaojusurvey.engine.core.user.UserService;
import com.xiaojusurvey.engine.repository.MongoRepository;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
import java.util.List;
@ -14,8 +20,27 @@ public class UserServiceImpl implements UserService {
@Resource
private MongoRepository mongoRepository;
@Override
public List<User> findAllUser() {
return mongoRepository.findAll(User.class);
}
/**
* 查询用户
* @param username
* @param password
* @return
*/
@Override
public User loadUserByUsernameAndPassword(String username, String password) {
Query query = new Query();
String encryptPassword = AuthUtil.encryptPassword(password, username);
query.addCriteria(Criteria.where("username").is(username).and("password").is(encryptPassword));
//查询用户并返回
User user = mongoRepository.findOne(query, User.class);
if (ObjectUtils.isEmpty(user)){
throw new ServiceException(RespErrorCode.USER_PASSWORD_ERROR.getMessage(), RespErrorCode.USER_PASSWORD_ERROR.getCode());
}
return user;
}
}

View File

@ -1,6 +1,7 @@
package com.xiaojusurvey.engine.repository;
import com.xiaojusurvey.engine.common.entity.BaseEntity;
import org.springframework.data.mongodb.core.query.Query;
import java.util.List;
@ -11,4 +12,8 @@ public interface MongoRepository {
<T extends BaseEntity> T findById(Object id, Class<T> entityClass);
<T extends BaseEntity> List<T> findAll(Class<T> entityClass);
<T extends BaseEntity> T findOne(Query query, Class<T> entityClass);
<T extends BaseEntity> void deleteById(Object id, Class<T> entityClass);
}

View File

@ -4,6 +4,8 @@ import com.xiaojusurvey.engine.common.entity.BaseEntity;
import com.xiaojusurvey.engine.common.exception.DaoException;
import com.xiaojusurvey.engine.repository.MongoRepository;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
@ -21,7 +23,7 @@ public class MongoRepositoryImpl implements MongoRepository {
@Override
public <T extends BaseEntity> T save(T saveObject) {
return null;
return mongoTemplate.save(saveObject);
}
@Override
@ -36,4 +38,16 @@ public class MongoRepositoryImpl implements MongoRepository {
public <T extends BaseEntity> List<T> findAll(Class<T> entityClass) {
return mongoTemplate.findAll(entityClass);
}
@Override
public <T extends BaseEntity> T findOne(Query query, Class<T> entityClass) {
return mongoTemplate.findOne(query,entityClass);
}
@Override
public <T extends BaseEntity> void deleteById(Object id, Class<T> entityClass) {
Query query = new Query(Criteria.where("_id").is(id));
mongoTemplate.remove(query, entityClass);
}
}

View File

@ -6,7 +6,8 @@
<parent>
<groupId>com.xiaojusurvey.engine</groupId>
<artifactId>survey-engine</artifactId>
<version>1.0.0</version>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>survey-extensions</artifactId>

View File

@ -19,10 +19,6 @@
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>

View File

@ -0,0 +1,32 @@
package com.xiaojusurvey.engine.aop;
import com.xiaojusurvey.engine.common.constants.RespErrorCode;
import com.xiaojusurvey.engine.common.rpc.RpcResult;
import com.xiaojusurvey.engine.common.util.RpcResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
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);
/**
* 自定义验证异常
*/
@ExceptionHandler(BindException.class)
public RpcResult handleBindException(BindException e) {
log.error(e.getMessage(), e);
String message = e.getAllErrors().get(0).getDefaultMessage();
return RpcResultUtil.createFailedResult(RespErrorCode.PARAMETER_ERROR.getCode(), message);
}
}

View File

@ -0,0 +1,59 @@
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.common.rpc.RpcResult;
import com.xiaojusurvey.engine.common.util.RpcResultUtil;
import com.xiaojusurvey.engine.core.auth.AuthService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @Author: LYF
* @CreateTime: 2024-06-06
* @Description: 登录/注册
*/
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Resource
private AuthService authService;
/**
* 获取验证码信息
* @return 结果
*/
@PostMapping("/captcha")
public RpcResult<CaptchaVo> captcha() {
return RpcResultUtil.createSuccessResult(authService.captcha());
}
/**
* 注册方法
* @return 结果
*/
@PostMapping("/register")
public RpcResult<UserVo> register(@Validated @RequestBody UserParam userParam) {
return RpcResultUtil.createSuccessResult(authService.register(userParam));
}
/**
* 登录方法
* @return 结果
*/
@PostMapping("/login")
public RpcResult<UserVo> login(@Validated @RequestBody UserParam userParam) {
return RpcResultUtil.createSuccessResult(authService.login(userParam));
}
}

View File

@ -0,0 +1,33 @@
package com.xiaojusurvey.engine.controller;
import com.xiaojusurvey.engine.common.entity.survey.SurveyMeta;
import com.xiaojusurvey.engine.core.reslut.IdResult;
import com.xiaojusurvey.engine.common.rpc.RpcResult;
import com.xiaojusurvey.engine.common.util.RpcResultUtil;
import com.xiaojusurvey.engine.core.survey.SurveyService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @Author: LYF
* @CreateTime: 2024-06-05
* @Description: 问卷Controller
*/
@RequestMapping("/api/survey")
@RestController
public class SurveyController {
@Resource
private SurveyService surveyService;
/**
* 创建问卷
*/
@RequestMapping("/createSurvey")
public RpcResult<IdResult> createSurvey(@Validated @RequestBody SurveyMeta surveyMeta) {
return RpcResultUtil.createSuccessResult(surveyService.createSurvey(surveyMeta));
}
}

View File

@ -1,6 +1,6 @@
package com.xiaojusurvey.engine.controller;
import com.xiaojusurvey.engine.common.entity.User;
import com.xiaojusurvey.engine.common.entity.user.User;
import com.xiaojusurvey.engine.common.rpc.RpcResult;
import com.xiaojusurvey.engine.common.util.RpcResultUtil;
import com.xiaojusurvey.engine.core.user.UserService;

View File

@ -1,15 +1,52 @@
package com.xiaojusurvey.engine.interceptor;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.xiaojusurvey.engine.common.constants.RespErrorCode;
import com.xiaojusurvey.engine.common.entity.user.User;
import com.xiaojusurvey.engine.common.exception.ServiceException;
import com.xiaojusurvey.engine.core.auth.util.JwtTokenUtil;
import com.xiaojusurvey.engine.core.user.UserService;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
public class LoginInterceptor implements HandlerInterceptor {
@Resource
private JwtTokenUtil jwtTokenUtil;
@Resource
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1:获取token jwt
DecodedJWT jwt = jwtTokenUtil.getTokenStrByRequest(request);
//2:判断token是否有效 && 是否过期
if (ObjectUtils.isEmpty(jwt)) {
//token找不到
throw new ServiceException(RespErrorCode.USER_CREDENTIALS_ERROR.getMessage(), RespErrorCode.USER_CREDENTIALS_ERROR.getCode());
}
if (jwt.getExpiresAt().getTime() < System.currentTimeMillis()) {
//token超时
throw new ServiceException(RespErrorCode.USER_CREDENTIALS_ERROR.getMessage(), RespErrorCode.USER_CREDENTIALS_ERROR.getCode());
}
//查询用户信息
Map<String, Claim> claims = jwt.getClaims();
//获取用户名,密码
String username = claims.get("username").asString();
String password = claims.get("password").asString();
//判空
if (ObjectUtils.isEmpty(username) || ObjectUtils.isEmpty(password)) {
//token超时
throw new ServiceException(RespErrorCode.USER_CREDENTIALS_ERROR.getMessage(), RespErrorCode.USER_CREDENTIALS_ERROR.getCode());
}
User user = userService.loadUserByUsernameAndPassword(username, password);
return HandlerInterceptor.super.preHandle(request, response, handler);
}
}

View File

@ -1,5 +1,6 @@
package com.xiaojusurvey.engine.interceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -7,11 +8,17 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class SurveyWebMvcConfigurer implements WebMvcConfigurer {
@Bean
public LoginInterceptor loginInterceptor(){
return new LoginInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
registry.addInterceptor(loginInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/auth/login", "/api/auth/register");
.excludePathPatterns("/api/auth/login", "/api/auth/register", "/api/auth/captcha");
}
}

View File

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

View File

@ -0,0 +1,63 @@
package com.xiaojusurvey.engine.controller;
import com.xiaojusurvey.engine.SurveyApplication;
import com.xiaojusurvey.engine.common.entity.user.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.util.JwtTokenUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
/**
* 问卷单元测试
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SurveyApplication.class)
public class AuthTest {
@Resource
private JwtTokenUtil jwtTokenUtil;
@Resource
AuthController authController;
@Test
public void captcha() {
RpcResult<CaptchaVo> captcha = authController.captcha();
System.out.println(captcha);
}
@Test
public void register() {
UserParam userParam = new UserParam();
userParam.setUsername("admin");
userParam.setPassword("admin");
userParam.setCaptchaId("666169681618c21f3f6b90cd");
userParam.setCaptcha("3377");
RpcResult<UserVo> register = authController.register(userParam);
System.out.println(register);
}
@Test
public void login() {
//eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzE3Njg4ODcyLCJqdGkiOiI4MDYwMDhhOC0xODVkLTQ1YjgtYmNhMy04YzRiNmRhN2IyNjcifQ.Sq2WMKsdOTqo-Xbw_g_FjQWv1pwRwWwUAJIDON9c2jA
UserParam userParam = new UserParam();
userParam.setUsername("admin");
userParam.setPassword("admin");
userParam.setCaptchaId("66617239de72dc5238d1c32e");
userParam.setCaptcha("1167");
RpcResult<UserVo> register = authController.login(userParam);
System.out.println(register);
}
}

View File

@ -0,0 +1,32 @@
package com.xiaojusurvey.engine.controller;
import com.xiaojusurvey.engine.SurveyApplication;
import com.xiaojusurvey.engine.common.entity.survey.SurveyMeta;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
/**
* 问卷单元测试
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SurveyApplication.class)
public class SurveyMetaTest {
@Resource
private SurveyController surveyController;
@Test
public void createSurvey() {
SurveyMeta surveyMeta = new SurveyMeta();
surveyMeta.setTitle("测试问卷");
surveyMeta.setSurveyType("1");
surveyMeta.setCreateMethod("1");
surveyMeta.setCreateFrom("1");
surveyController.createSurvey(surveyMeta);
}
}

View File

@ -1,8 +1,7 @@
package com.xiaojusurvey.engine.controller;
import com.alibaba.fastjson.JSON;
import com.xiaojusurvey.engine.SurveyApplication;
import com.xiaojusurvey.engine.common.entity.User;
import com.xiaojusurvey.engine.common.entity.user.User;
import com.xiaojusurvey.engine.common.rpc.RpcResult;
import com.xiaojusurvey.engine.core.user.UserService;
import org.junit.Assert;