Compare commits
No commits in common. 'develop' and 'soul2/mobile_api' have entirely different histories.
develop
...
soul2/mobi
66 changed files with 111 additions and 2518 deletions
@ -1,18 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* 跳过加解密 |
|
||||||
* |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-04-08 |
|
||||||
*/ |
|
||||||
@Target({ElementType.METHOD, ElementType.TYPE}) |
|
||||||
@Retention(RetentionPolicy.RUNTIME) |
|
||||||
public @interface SkinEncrypt { |
|
||||||
|
|
||||||
} |
|
@ -1,15 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-04-02 |
|
||||||
*/ |
|
||||||
@Target({ElementType.METHOD, ElementType.TYPE}) |
|
||||||
@Retention(RetentionPolicy.RUNTIME) |
|
||||||
public @interface SkinLogin { |
|
||||||
} |
|
@ -1,99 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.bean; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.entity.UserLoginOutDO; |
|
||||||
import org.apache.commons.lang3.StringUtils; |
|
||||||
import org.springframework.stereotype.Component; |
|
||||||
|
|
||||||
import java.time.LocalDateTime; |
|
||||||
import java.util.Collection; |
|
||||||
import java.util.concurrent.ConcurrentHashMap; |
|
||||||
|
|
||||||
@Component |
|
||||||
public class UserLoginStatusBean { |
|
||||||
|
|
||||||
private ConcurrentHashMap<String, UserLoginOutDO> loginStatusMap = new ConcurrentHashMap<>(); |
|
||||||
|
|
||||||
public void loadUserLoginStatus(Collection<UserLoginOutDO> caches) { |
|
||||||
for (UserLoginOutDO cache : caches) { |
|
||||||
loginStatusMap.put(cache.getId(), cache); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 缓存登录信息 |
|
||||||
* |
|
||||||
* @param token token |
|
||||||
* @param loginOutStatus 登录信息 |
|
||||||
*/ |
|
||||||
public void login(String token, UserLoginOutDO loginOutStatus) { |
|
||||||
loginStatusMap.put(token, loginOutStatus); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 从缓存读取登录信息 |
|
||||||
* |
|
||||||
* @param token token |
|
||||||
* @return {@link UserLoginOutDO} |
|
||||||
*/ |
|
||||||
public UserLoginOutDO getStatus(String token) { |
|
||||||
UserLoginOutDO loginStatus = loginStatusMap.getOrDefault(token, null); |
|
||||||
if (loginStatus.getLapseTime() != null) { |
|
||||||
LocalDateTime now = LocalDateTime.now(); |
|
||||||
if (now.isAfter(loginStatus.getLapseTime())) { |
|
||||||
logout(token); |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
return loginStatus; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 为key设置登出 |
|
||||||
* |
|
||||||
* @param token token |
|
||||||
* @return {@link Boolean} |
|
||||||
*/ |
|
||||||
public Boolean logout(String token) { |
|
||||||
if (StringUtils.isNotBlank(token) && loginStatusMap.containsKey(token)) { |
|
||||||
UserLoginOutDO removedUser = loginStatusMap.remove(token); |
|
||||||
// 返回true表示成功登出,返回false表示未成功登出
|
|
||||||
return removedUser != null; |
|
||||||
} |
|
||||||
return Boolean.TRUE; |
|
||||||
} |
|
||||||
|
|
||||||
public Boolean logoutByUserId(String userId) { |
|
||||||
final String[] targetKey = {null}; |
|
||||||
loginStatusMap.forEach((k, v) -> { |
|
||||||
if (targetKey[0] == null && v.getUserId().equals(userId)) { |
|
||||||
targetKey[0] = k; |
|
||||||
} |
|
||||||
}); |
|
||||||
return logout(targetKey[0]); |
|
||||||
} |
|
||||||
|
|
||||||
public String getTokenByUsername(String username) { |
|
||||||
final String[] token = {null}; |
|
||||||
loginStatusMap.forEach((k, v) -> { |
|
||||||
if (token[0] == null && v.getUserName().equals(username)) { |
|
||||||
token[0] = k; |
|
||||||
} |
|
||||||
}); |
|
||||||
return token[0]; |
|
||||||
} |
|
||||||
|
|
||||||
public Boolean containsToken(String token) { |
|
||||||
if (StringUtils.isBlank(token)) { |
|
||||||
return Boolean.FALSE; |
|
||||||
} |
|
||||||
UserLoginOutDO loginStatus = loginStatusMap.getOrDefault(token, null); |
|
||||||
if (loginStatus != null && loginStatus.getLapseTime() != null) { |
|
||||||
LocalDateTime now = LocalDateTime.now(); |
|
||||||
if (now.isAfter(loginStatus.getLapseTime())) { |
|
||||||
logout(token); |
|
||||||
} |
|
||||||
} |
|
||||||
return loginStatusMap.containsKey(token); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,65 @@ |
|||||||
|
package cn.soul2.jyjc.admin.config; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.web.servlet.config.annotation.CorsRegistry; |
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Soul2 |
||||||
|
* @date 2024-03-25 |
||||||
|
*/ |
||||||
|
@Configuration |
||||||
|
public class CorsConfig implements WebMvcConfigurer { |
||||||
|
|
||||||
|
@Value("${cors.allow-origins}") |
||||||
|
private String[] allowOriginArray; |
||||||
|
|
||||||
|
/** |
||||||
|
* 将数组转换为List进行动态添加 |
||||||
|
*/ |
||||||
|
private final List<String> allowOriginList = new ArrayList<>(); |
||||||
|
|
||||||
|
// private static boolean isLocalV4Address(String ipAddress) {
|
||||||
|
// // todo 为进行手机测试而增加的读取内网IP,正式上线时须注释掉
|
||||||
|
// String[] parts = ipAddress.split("\\.");
|
||||||
|
// // 判断是否是有效的IPv4地址并且属于局域网
|
||||||
|
// return parts.length == 4 && parts[0].equals("192") && parts[1].equals("168");
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void addCorsMappings(CorsRegistry registry) { |
||||||
|
allowOriginList.addAll(Arrays.asList(allowOriginArray)); |
||||||
|
// // todo 为进行手机测试而增加的读取内网IP,正式上线时须注释掉
|
||||||
|
// try {
|
||||||
|
// Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
|
||||||
|
// while (networkInterfaces.hasMoreElements()) {
|
||||||
|
// NetworkInterface networkInterface = networkInterfaces.nextElement();
|
||||||
|
// Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
|
||||||
|
// while (inetAddresses.hasMoreElements()) {
|
||||||
|
// InetAddress inetAddress = inetAddresses.nextElement();
|
||||||
|
// if (isLocalV4Address(inetAddress.getHostAddress())) {
|
||||||
|
// System.out.println("Local IPv4 Address: " + inetAddress.getHostAddress());
|
||||||
|
// allowOriginList.add("http://" + inetAddress.getHostAddress() + ":7620");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 打印 allowOriginList 到控制台
|
||||||
|
// System.out.println("allowOriginList: " + allowOriginList);
|
||||||
|
|
||||||
|
registry.addMapping("/**") |
||||||
|
.allowedOrigins(allowOriginList.toArray(new String[0])) |
||||||
|
.allowCredentials(true) |
||||||
|
.allowedMethods("POST") |
||||||
|
.maxAge(3600); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,41 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.config; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.filter.ReplaceStreamFilter; |
|
||||||
import org.springframework.boot.web.servlet.FilterRegistrationBean; |
|
||||||
import org.springframework.context.annotation.Bean; |
|
||||||
import org.springframework.context.annotation.Configuration; |
|
||||||
|
|
||||||
import javax.servlet.Filter; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @description 过滤器配置类 |
|
||||||
* @date 2024-04-08 |
|
||||||
* <p>照抄自 <a href="https://blog.csdn.net/shaoduo/article/details/122322578">Shao duo</a></p> |
|
||||||
*/ |
|
||||||
@Configuration |
|
||||||
public class FilterConfig { |
|
||||||
/** |
|
||||||
* 注册过滤器 |
|
||||||
* |
|
||||||
* @return FilterRegistrationBean |
|
||||||
*/ |
|
||||||
@Bean |
|
||||||
public FilterRegistrationBean someFilterRegistration() { |
|
||||||
FilterRegistrationBean registration = new FilterRegistrationBean(); |
|
||||||
registration.setFilter(replaceStreamFilter()); |
|
||||||
registration.addUrlPatterns("/*"); |
|
||||||
registration.setName("streamFilter"); |
|
||||||
return registration; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 实例化StreamFilter |
|
||||||
* |
|
||||||
* @return Filter |
|
||||||
*/ |
|
||||||
@Bean(name = "replaceStreamFilter") |
|
||||||
public Filter replaceStreamFilter() { |
|
||||||
return new ReplaceStreamFilter(); |
|
||||||
} |
|
||||||
} |
|
@ -1,67 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.config; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.interceptor.FinallyInterceptor; |
|
||||||
import org.springframework.beans.factory.annotation.Value; |
|
||||||
import org.springframework.context.annotation.Bean; |
|
||||||
import org.springframework.context.annotation.Configuration; |
|
||||||
import org.springframework.web.cors.CorsConfiguration; |
|
||||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
|
||||||
import org.springframework.web.filter.CorsFilter; |
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; |
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
|
||||||
|
|
||||||
/** |
|
||||||
* 注册拦截器 |
|
||||||
* |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-04-02 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Configuration |
|
||||||
public class WebMvcConfig implements WebMvcConfigurer { |
|
||||||
|
|
||||||
@Value("${cors.allow-origin}") |
|
||||||
private String[] allowOrigin; |
|
||||||
|
|
||||||
@Bean |
|
||||||
public CorsFilter corsFilter() { |
|
||||||
CorsConfiguration config = new CorsConfiguration(); |
|
||||||
// 设置允许跨域请求的域名
|
|
||||||
for (String url : allowOrigin) { |
|
||||||
config.addAllowedOrigin(url); |
|
||||||
} |
|
||||||
// 是否允许证书 不再默认开启
|
|
||||||
// config.setAllowCredentials(true);
|
|
||||||
// 设置允许的方法
|
|
||||||
config.addAllowedMethod("*"); |
|
||||||
// 允许任何头
|
|
||||||
config.addAllowedHeader("*"); |
|
||||||
config.addExposedHeader("token"); |
|
||||||
config.setMaxAge(3600L); |
|
||||||
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(); |
|
||||||
configSource.registerCorsConfiguration("/**", config); |
|
||||||
return new CorsFilter(configSource); |
|
||||||
} |
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public void addCorsMappings(CorsRegistry registry) {
|
|
||||||
// registry.addMapping("/**")
|
|
||||||
// .allowedHeaders("*")
|
|
||||||
// .allowedOrigins(allowOrigin)
|
|
||||||
// .allowCredentials(true)
|
|
||||||
// .allowedMethods("POST")
|
|
||||||
// .maxAge(3600);
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Bean |
|
||||||
FinallyInterceptor createFinallyInterceptor() { |
|
||||||
return new FinallyInterceptor(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void addInterceptors(InterceptorRegistry registry) { |
|
||||||
registry.addInterceptor(createFinallyInterceptor()) |
|
||||||
// 拦截所有路径
|
|
||||||
.addPathPatterns("/**"); |
|
||||||
} |
|
||||||
} |
|
@ -1,41 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.controller; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.dto.AnswerPageQueryDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.AnswerSubmitDTO; |
|
||||||
import cn.soul2.jyjc.admin.service.IAnswerService; |
|
||||||
import cn.soul2.jyjc.admin.utils.base.BackUtils; |
|
||||||
import cn.soul2.jyjc.admin.vo.AnswerSheetVO; |
|
||||||
import cn.soul2.jyjc.admin.vo.base.Back; |
|
||||||
import cn.soul2.jyjc.admin.vo.base.VPage; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||||
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; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-27 13:24 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Slf4j |
|
||||||
@RestController |
|
||||||
@RequestMapping("/answer") |
|
||||||
public class AnswerController { |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private IAnswerService answerService; |
|
||||||
|
|
||||||
@PostMapping("submit") |
|
||||||
public Back<Boolean> submit(@RequestBody AnswerSubmitDTO dto) { |
|
||||||
return BackUtils.success(answerService.handleSubmit(dto)); |
|
||||||
} |
|
||||||
|
|
||||||
@PostMapping("page") |
|
||||||
public Back<VPage<AnswerSheetVO>> page(@RequestBody AnswerPageQueryDTO dto) { |
|
||||||
return BackUtils.success(answerService.page(dto)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
} |
|
@ -1,47 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.controller; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.annotation.SkinLogin; |
|
||||||
import cn.soul2.jyjc.admin.dto.UserLoginDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.UserLogoutDTO; |
|
||||||
import cn.soul2.jyjc.admin.service.IUserService; |
|
||||||
import cn.soul2.jyjc.admin.utils.base.BackUtils; |
|
||||||
import cn.soul2.jyjc.admin.vo.UserVO; |
|
||||||
import cn.soul2.jyjc.admin.vo.base.Back; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||||
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; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-31 15:48 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Slf4j |
|
||||||
@RestController |
|
||||||
@RequestMapping("/user") |
|
||||||
public class UserController { |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private IUserService userService; |
|
||||||
|
|
||||||
@PostMapping("login") |
|
||||||
@SkinLogin |
|
||||||
public Back<UserVO> login(@RequestBody UserLoginDTO dto) { |
|
||||||
return BackUtils.success(userService.login(dto)); |
|
||||||
} |
|
||||||
|
|
||||||
@PostMapping("register") |
|
||||||
@SkinLogin |
|
||||||
public Back<UserVO> register(@RequestBody UserLoginDTO dto) { |
|
||||||
return BackUtils.success(userService.register(dto)); |
|
||||||
} |
|
||||||
|
|
||||||
@PostMapping("logout") |
|
||||||
public Back<Boolean> logout(@RequestBody UserLogoutDTO dto) { |
|
||||||
return BackUtils.success(userService.logout(dto)); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,45 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.dto; |
|
||||||
|
|
||||||
import lombok.Data; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-27 13:31 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Data |
|
||||||
@Accessors(chain = true) |
|
||||||
public class AnswerDetailDTO { |
|
||||||
|
|
||||||
/** |
|
||||||
* 回答内容(文字/选项id,多选时以,分隔) |
|
||||||
*/ |
|
||||||
private String content; |
|
||||||
|
|
||||||
/** |
|
||||||
* 得分 |
|
||||||
*/ |
|
||||||
private Integer points; |
|
||||||
|
|
||||||
/** |
|
||||||
* 题目id |
|
||||||
*/ |
|
||||||
private String subjectId; |
|
||||||
|
|
||||||
/** |
|
||||||
* 题目类型:0-单选;1-多选;2-文字 |
|
||||||
*/ |
|
||||||
private Integer subjectType; |
|
||||||
|
|
||||||
/** |
|
||||||
* 题目分值 |
|
||||||
*/ |
|
||||||
private Integer subjectPoints; |
|
||||||
|
|
||||||
/** |
|
||||||
* 权重 |
|
||||||
*/ |
|
||||||
private Double weights; |
|
||||||
|
|
||||||
} |
|
@ -1,21 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.dto; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.dto.base.PageParams; |
|
||||||
import lombok.Data; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-05-10 11:48 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Data |
|
||||||
@Accessors(chain = true) |
|
||||||
public class AnswerSheetQueryDTO extends PageParams { |
|
||||||
|
|
||||||
/** |
|
||||||
* sheet id |
|
||||||
*/ |
|
||||||
private String sheetId; |
|
||||||
|
|
||||||
} |
|
@ -1,37 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.dto; |
|
||||||
|
|
||||||
import lombok.Data; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-27 13:26 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Data |
|
||||||
@Accessors(chain = true) |
|
||||||
public class AnswerSubmitDTO { |
|
||||||
|
|
||||||
/** |
|
||||||
* 二维码id |
|
||||||
*/ |
|
||||||
private String qrId; |
|
||||||
|
|
||||||
/** |
|
||||||
* 问卷Id |
|
||||||
*/ |
|
||||||
private String qnId; |
|
||||||
|
|
||||||
/** |
|
||||||
* openid, 即答卷人 |
|
||||||
*/ |
|
||||||
private String openid; |
|
||||||
|
|
||||||
/** |
|
||||||
* 答题内容 |
|
||||||
*/ |
|
||||||
private List<AnswerDetailDTO> details; |
|
||||||
|
|
||||||
} |
|
@ -1,21 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.dto; |
|
||||||
|
|
||||||
import lombok.Data; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-05-10 15:06 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Data |
|
||||||
@Accessors(chain = true) |
|
||||||
public class QnOptionsDTO { |
|
||||||
|
|
||||||
/** |
|
||||||
* 查询状态 -1 or null: 所有 |
|
||||||
*/ |
|
||||||
private Integer status; |
|
||||||
|
|
||||||
|
|
||||||
} |
|
@ -1,30 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.dto; |
|
||||||
|
|
||||||
import lombok.Data; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-29 21:55 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Data |
|
||||||
@Accessors(chain = true) |
|
||||||
public class UserLoginDTO { |
|
||||||
|
|
||||||
/** |
|
||||||
* userName |
|
||||||
*/ |
|
||||||
private String username; |
|
||||||
|
|
||||||
/** |
|
||||||
* password |
|
||||||
*/ |
|
||||||
private String password; |
|
||||||
|
|
||||||
/** |
|
||||||
* 密码错误次数(暂未使用) |
|
||||||
*/ |
|
||||||
private Integer pswErrorCount; |
|
||||||
|
|
||||||
} |
|
@ -1,21 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.dto; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.dto.base.PageParams; |
|
||||||
import lombok.Data; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-29 21:50 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Data |
|
||||||
@Accessors(chain = true) |
|
||||||
public class UserLoginOutPageDTO extends PageParams { |
|
||||||
|
|
||||||
/** |
|
||||||
* userId |
|
||||||
*/ |
|
||||||
private String userId; |
|
||||||
|
|
||||||
} |
|
@ -1,25 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.dto; |
|
||||||
|
|
||||||
import lombok.Data; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-29 21:56 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Data |
|
||||||
@Accessors(chain = true) |
|
||||||
public class UserLogoutDTO { |
|
||||||
|
|
||||||
/** |
|
||||||
* userName |
|
||||||
*/ |
|
||||||
private String username; |
|
||||||
|
|
||||||
/** |
|
||||||
* token |
|
||||||
*/ |
|
||||||
private String token; |
|
||||||
|
|
||||||
} |
|
@ -1,37 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.dto; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.dto.base.PageParams; |
|
||||||
import lombok.Data; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
import java.time.LocalDateTime; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-29 20:50 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Data |
|
||||||
@Accessors(chain = true) |
|
||||||
public class UserPageDTO extends PageParams { |
|
||||||
|
|
||||||
/** |
|
||||||
* id |
|
||||||
*/ |
|
||||||
private String id; |
|
||||||
/** |
|
||||||
* 用户名 |
|
||||||
*/ |
|
||||||
private String username; |
|
||||||
/** |
|
||||||
* 状态;0(默认):正常;4:封号;9:异常; |
|
||||||
*/ |
|
||||||
private Integer status; |
|
||||||
|
|
||||||
/** |
|
||||||
* 注册时间 |
|
||||||
*/ |
|
||||||
private LocalDateTime startTime; |
|
||||||
private LocalDateTime endTime; |
|
||||||
|
|
||||||
} |
|
@ -1,45 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.dto; |
|
||||||
|
|
||||||
import lombok.Data; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-29 20:50 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Data |
|
||||||
@Accessors(chain = true) |
|
||||||
public class UserSaveDTO { |
|
||||||
|
|
||||||
/** |
|
||||||
* id |
|
||||||
*/ |
|
||||||
private String id; |
|
||||||
|
|
||||||
/** |
|
||||||
* 用户名 |
|
||||||
*/ |
|
||||||
private String username; |
|
||||||
|
|
||||||
/** |
|
||||||
* 密码 |
|
||||||
*/ |
|
||||||
private String password; |
|
||||||
|
|
||||||
/** |
|
||||||
* 状态;0(默认):正常;4:封号;9:异常; |
|
||||||
*/ |
|
||||||
private Integer status; |
|
||||||
|
|
||||||
/** |
|
||||||
* 权限等级,默认200 |
|
||||||
*/ |
|
||||||
private Integer authorityLevel; |
|
||||||
|
|
||||||
/** |
|
||||||
* 密码修改次数 |
|
||||||
*/ |
|
||||||
private Integer pswChange; |
|
||||||
|
|
||||||
} |
|
@ -1,93 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.entity; |
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.*; |
|
||||||
import com.baomidou.mybatisplus.extension.activerecord.Model; |
|
||||||
import lombok.Getter; |
|
||||||
import lombok.Setter; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
import java.io.Serializable; |
|
||||||
import java.time.LocalDateTime; |
|
||||||
|
|
||||||
/** |
|
||||||
* <p> |
|
||||||
* 用户表 |
|
||||||
* </p> |
|
||||||
* |
|
||||||
* @author Soul2 |
|
||||||
* @since 2024-03-30 14:34:13 |
|
||||||
*/ |
|
||||||
@Getter |
|
||||||
@Setter |
|
||||||
@Accessors(chain = true) |
|
||||||
@TableName("tb_user") |
|
||||||
public class UserDO extends Model<UserDO> { |
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L; |
|
||||||
|
|
||||||
/** |
|
||||||
* id |
|
||||||
*/ |
|
||||||
@TableId(value = "id", type = IdType.ASSIGN_UUID) |
|
||||||
private String id; |
|
||||||
|
|
||||||
/** |
|
||||||
* 用户名 |
|
||||||
*/ |
|
||||||
@TableField("username") |
|
||||||
private String username; |
|
||||||
|
|
||||||
/** |
|
||||||
* 密码 |
|
||||||
*/ |
|
||||||
@TableField("password") |
|
||||||
private String password; |
|
||||||
|
|
||||||
/** |
|
||||||
* 状态;0(默认):正常;4:封号;9:异常; |
|
||||||
*/ |
|
||||||
@TableField("status") |
|
||||||
private Integer status; |
|
||||||
|
|
||||||
/** |
|
||||||
* 权限等级,默认200 |
|
||||||
*/ |
|
||||||
@TableField("authority_level") |
|
||||||
private Integer authorityLevel; |
|
||||||
|
|
||||||
/** |
|
||||||
* 密码修改次数 |
|
||||||
*/ |
|
||||||
@TableField("psw_change") |
|
||||||
private Integer pswChange; |
|
||||||
|
|
||||||
/** |
|
||||||
* 更新时间 |
|
||||||
*/ |
|
||||||
@TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE) |
|
||||||
private LocalDateTime updatedTime; |
|
||||||
|
|
||||||
/** |
|
||||||
* 创建时间 |
|
||||||
*/ |
|
||||||
@TableField(value = "created_time", fill = FieldFill.INSERT) |
|
||||||
private LocalDateTime createdTime; |
|
||||||
|
|
||||||
/** |
|
||||||
* 删除标记 |
|
||||||
*/ |
|
||||||
@TableField("removed") |
|
||||||
@TableLogic |
|
||||||
private Integer removed; |
|
||||||
|
|
||||||
/** |
|
||||||
* 盐,用于密码加密,未启用 |
|
||||||
*/ |
|
||||||
@TableField("salt") |
|
||||||
private String salt; |
|
||||||
|
|
||||||
@Override |
|
||||||
public Serializable pkVal() { |
|
||||||
return this.id; |
|
||||||
} |
|
||||||
} |
|
@ -1,87 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.entity; |
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.*; |
|
||||||
import com.baomidou.mybatisplus.extension.activerecord.Model; |
|
||||||
import lombok.Getter; |
|
||||||
import lombok.Setter; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
import java.io.Serializable; |
|
||||||
import java.time.LocalDateTime; |
|
||||||
|
|
||||||
/** |
|
||||||
* <p> |
|
||||||
* 用户登入登出表 |
|
||||||
* </p> |
|
||||||
* |
|
||||||
* @author Soul2 |
|
||||||
* @since 2024-03-30 13:57:00 |
|
||||||
*/ |
|
||||||
@Getter |
|
||||||
@Setter |
|
||||||
@Accessors(chain = true) |
|
||||||
@TableName("tb_user_login_out") |
|
||||||
public class UserLoginOutDO extends Model<UserLoginOutDO> { |
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L; |
|
||||||
|
|
||||||
/** |
|
||||||
* id |
|
||||||
*/ |
|
||||||
@TableId(value = "id", type = IdType.ASSIGN_UUID) |
|
||||||
private String id; |
|
||||||
|
|
||||||
/** |
|
||||||
* 用户id |
|
||||||
*/ |
|
||||||
@TableField("user_id") |
|
||||||
private String userId; |
|
||||||
|
|
||||||
/** |
|
||||||
* 用户名称 |
|
||||||
*/ |
|
||||||
@TableField("user_name") |
|
||||||
private String userName; |
|
||||||
|
|
||||||
/** |
|
||||||
* 登录时间,登录成功才写入 |
|
||||||
*/ |
|
||||||
@TableField("login_time") |
|
||||||
private LocalDateTime loginTime; |
|
||||||
|
|
||||||
/** |
|
||||||
* 登录失效时间 |
|
||||||
*/ |
|
||||||
@TableField("lapse_time") |
|
||||||
private LocalDateTime lapseTime; |
|
||||||
|
|
||||||
/** |
|
||||||
* 用户操作登出时间 |
|
||||||
*/ |
|
||||||
@TableField("logout_time") |
|
||||||
private LocalDateTime logoutTime; |
|
||||||
|
|
||||||
/** |
|
||||||
* 密码错误次数 |
|
||||||
*/ |
|
||||||
@TableField("psw_error_count") |
|
||||||
private Integer pswErrorCount; |
|
||||||
|
|
||||||
/** |
|
||||||
* 创建时间 |
|
||||||
*/ |
|
||||||
@TableField(value = "created_time", fill = FieldFill.INSERT) |
|
||||||
private LocalDateTime createdTime; |
|
||||||
|
|
||||||
/** |
|
||||||
* 1=删除;0=未删除 |
|
||||||
*/ |
|
||||||
@TableField("removed") |
|
||||||
@TableLogic |
|
||||||
private Integer removed; |
|
||||||
|
|
||||||
@Override |
|
||||||
public Serializable pkVal() { |
|
||||||
return this.id; |
|
||||||
} |
|
||||||
} |
|
@ -1,60 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.filter; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.utils.EncryptUtils; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload; |
|
||||||
|
|
||||||
import javax.servlet.*; |
|
||||||
import javax.servlet.http.HttpServletRequest; |
|
||||||
import javax.servlet.http.HttpServletResponse; |
|
||||||
import java.io.IOException; |
|
||||||
import java.io.PrintWriter; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author shaoduo |
|
||||||
* @description 替换HttpServletRequest |
|
||||||
* @since 1.0 |
|
||||||
**/ |
|
||||||
@Slf4j |
|
||||||
public class ReplaceStreamFilter implements Filter { |
|
||||||
@Override |
|
||||||
public void init(FilterConfig filterConfig) throws ServletException { |
|
||||||
log.info("StreamFilter初始化..."); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { |
|
||||||
//如果是文件上传则会报错可以判断是否是文件上传不读取流即可
|
|
||||||
if (ServletFileUpload.isMultipartContent((HttpServletRequest) request)) { |
|
||||||
chain.doFilter(request, response); |
|
||||||
} else if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) request).getMethod())) { |
|
||||||
chain.doFilter(request, response); |
|
||||||
} else { |
|
||||||
ServletRequest requestWrapper = new ShaoduoRequestWrapper((HttpServletRequest) request); |
|
||||||
// System.out.printf("ReplaceStreamFilter触发, Method: %s, URI: %s%n", ((HttpServletRequest) request).getMethod(), ((HttpServletRequest) request).getRequestURI());
|
|
||||||
HttpServletResponse httpResponse = (HttpServletResponse) response; |
|
||||||
Soul2ResponseWrapper soul2ResponseWrapper = new Soul2ResponseWrapper(httpResponse); |
|
||||||
chain.doFilter(requestWrapper, soul2ResponseWrapper); |
|
||||||
try { |
|
||||||
byte[] data = soul2ResponseWrapper.getResponseData(); |
|
||||||
log.debug("原始返回 -> " + new String(data)); |
|
||||||
String encryptBody = EncryptUtils.encrypt(new String(data)); |
|
||||||
log.debug("加密返回 -> " + encryptBody); |
|
||||||
soul2ResponseWrapper.setHeader("encrypt", "1"); |
|
||||||
soul2ResponseWrapper.setHeader("Access-Control-Expose-Headers", "encrypt"); |
|
||||||
PrintWriter out = response.getWriter(); |
|
||||||
out.print(encryptBody); |
|
||||||
out.flush(); |
|
||||||
out.close(); |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void destroy() { |
|
||||||
log.info("StreamFilter销毁..."); |
|
||||||
} |
|
||||||
} |
|
@ -1,130 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.filter; |
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
|
|
||||||
import javax.servlet.ReadListener; |
|
||||||
import javax.servlet.ServletInputStream; |
|
||||||
import javax.servlet.ServletRequest; |
|
||||||
import javax.servlet.http.HttpServletRequest; |
|
||||||
import javax.servlet.http.HttpServletRequestWrapper; |
|
||||||
import java.io.*; |
|
||||||
import java.nio.charset.Charset; |
|
||||||
import java.nio.charset.StandardCharsets; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author shaoduo |
|
||||||
* @description 包装HttpServletRequest,目的是让其输入流可重复读 |
|
||||||
* @since <a href="https://blog.csdn.net/shaoduo/article/details/122322578">shaoduo</a> |
|
||||||
**/ |
|
||||||
@Slf4j |
|
||||||
public class ShaoduoRequestWrapper extends HttpServletRequestWrapper { |
|
||||||
/** |
|
||||||
* 存储body数据的容器 |
|
||||||
*/ |
|
||||||
private byte[] body; |
|
||||||
|
|
||||||
public ShaoduoRequestWrapper(HttpServletRequest request) { |
|
||||||
super(request); |
|
||||||
|
|
||||||
// 将body数据存储起来
|
|
||||||
String bodyStr = getBodyString(request); |
|
||||||
body = bodyStr.getBytes(Charset.defaultCharset()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取请求Body |
|
||||||
* |
|
||||||
* @param request request |
|
||||||
* @return String |
|
||||||
*/ |
|
||||||
public String getBodyString(final ServletRequest request) { |
|
||||||
try { |
|
||||||
return inputStream2String(request.getInputStream()); |
|
||||||
} catch (IOException e) { |
|
||||||
log.error("", e); |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取请求Body |
|
||||||
* |
|
||||||
* @return String |
|
||||||
*/ |
|
||||||
public String getBodyString() throws IOException { |
|
||||||
InputStream inputStream = new ByteArrayInputStream(body); |
|
||||||
return inputStream2String(inputStream); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 修改body 将json 重新设置成body |
|
||||||
* |
|
||||||
* @param val |
|
||||||
*/ |
|
||||||
public void setBody(String val) { |
|
||||||
body = val.getBytes(StandardCharsets.UTF_8); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 将inputStream里的数据读取出来并转换成字符串 |
|
||||||
* |
|
||||||
* @param inputStream inputStream |
|
||||||
* @return String |
|
||||||
*/ |
|
||||||
private String inputStream2String(InputStream inputStream) throws IOException { |
|
||||||
StringBuilder sb = new StringBuilder(); |
|
||||||
BufferedReader reader = null; |
|
||||||
|
|
||||||
try { |
|
||||||
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset())); |
|
||||||
String line; |
|
||||||
while ((line = reader.readLine()) != null) { |
|
||||||
sb.append(line); |
|
||||||
} |
|
||||||
} catch (IOException e) { |
|
||||||
log.error("", e); |
|
||||||
throw new RuntimeException(e); |
|
||||||
} finally { |
|
||||||
if (reader != null) { |
|
||||||
try { |
|
||||||
reader.close(); |
|
||||||
} catch (IOException e) { |
|
||||||
log.error("", e); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return sb.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public BufferedReader getReader() throws IOException { |
|
||||||
return new BufferedReader(new InputStreamReader(getInputStream())); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public ServletInputStream getInputStream() { |
|
||||||
|
|
||||||
final ByteArrayInputStream inputStream = new ByteArrayInputStream(body); |
|
||||||
|
|
||||||
return new ServletInputStream() { |
|
||||||
@Override |
|
||||||
public int read() { |
|
||||||
return inputStream.read(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isFinished() { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isReady() { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setReadListener(ReadListener readListener) { |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
@ -1,120 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.filter; |
|
||||||
|
|
||||||
import lombok.SneakyThrows; |
|
||||||
|
|
||||||
import javax.servlet.ServletOutputStream; |
|
||||||
import javax.servlet.WriteListener; |
|
||||||
import javax.servlet.http.HttpServletResponse; |
|
||||||
import javax.servlet.http.HttpServletResponseWrapper; |
|
||||||
import java.io.*; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @description 包装ServletResponse, 照抄自 <a href="https://blog.csdn.net/temp_44/article/details/107762290">temp_44</a> |
|
||||||
* @date 2024-04-15 |
|
||||||
*/ |
|
||||||
public class Soul2ResponseWrapper extends HttpServletResponseWrapper { |
|
||||||
private ByteArrayOutputStream buffer = null; |
|
||||||
private ServletOutputStream out = null; |
|
||||||
private PrintWriter writer = null; |
|
||||||
|
|
||||||
public Soul2ResponseWrapper(HttpServletResponse resp) throws IOException { |
|
||||||
super(resp); |
|
||||||
// 真正存储数据的流
|
|
||||||
buffer = new ByteArrayOutputStream(); |
|
||||||
out = new WapperedOutputStream(buffer); |
|
||||||
writer = new PrintWriter(new OutputStreamWriter(buffer, |
|
||||||
this.getCharacterEncoding())); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 重载父类获取outputstream的方法 |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public ServletOutputStream getOutputStream() throws IOException { |
|
||||||
return out; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 重载父类获取writer的方法 |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public PrintWriter getWriter() throws UnsupportedEncodingException { |
|
||||||
return writer; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* The default behavior of this method is to call |
|
||||||
* setCharacterEncoding(String charset) on the wrapped response object. |
|
||||||
* |
|
||||||
* @param charset |
|
||||||
* @since 2.4 |
|
||||||
*/ |
|
||||||
@SneakyThrows |
|
||||||
@Override |
|
||||||
public void setCharacterEncoding(String charset) { |
|
||||||
super.setCharacterEncoding(charset); |
|
||||||
writer = new PrintWriter(new OutputStreamWriter(buffer, |
|
||||||
this.getCharacterEncoding())); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 重载父类获取flushBuffer的方法 |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public void flushBuffer() throws IOException { |
|
||||||
if (out != null) { |
|
||||||
out.flush(); |
|
||||||
} |
|
||||||
if (writer != null) { |
|
||||||
writer.flush(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void reset() { |
|
||||||
buffer.reset(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据 |
|
||||||
*/ |
|
||||||
public byte[] getResponseData() throws IOException { |
|
||||||
flushBuffer(); |
|
||||||
return buffer.toByteArray(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 内部类,对ServletOutputStream进行包装 |
|
||||||
*/ |
|
||||||
private class WapperedOutputStream extends ServletOutputStream { |
|
||||||
private ByteArrayOutputStream bos = null; |
|
||||||
|
|
||||||
public WapperedOutputStream(ByteArrayOutputStream stream) |
|
||||||
throws IOException { |
|
||||||
bos = stream; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void write(int b) throws IOException { |
|
||||||
bos.write(b); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void write(byte[] b) throws IOException { |
|
||||||
bos.write(b, 0, b.length); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean isReady() { |
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setWriteListener(WriteListener writeListener) { |
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,137 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.interceptor; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.annotation.SkinEncrypt; |
|
||||||
import cn.soul2.jyjc.admin.annotation.SkinLogin; |
|
||||||
import cn.soul2.jyjc.admin.bean.UserLoginStatusBean; |
|
||||||
import cn.soul2.jyjc.admin.filter.ShaoduoRequestWrapper; |
|
||||||
import cn.soul2.jyjc.admin.service.IUserService; |
|
||||||
import cn.soul2.jyjc.admin.utils.EncryptUtils; |
|
||||||
import cn.soul2.jyjc.admin.vo.base.Back; |
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||||
import org.springframework.web.method.HandlerMethod; |
|
||||||
import org.springframework.web.servlet.HandlerInterceptor; |
|
||||||
|
|
||||||
import javax.annotation.Resource; |
|
||||||
import javax.servlet.http.HttpServletRequest; |
|
||||||
import javax.servlet.http.HttpServletResponse; |
|
||||||
import java.io.PrintWriter; |
|
||||||
import java.lang.reflect.Method; |
|
||||||
|
|
||||||
/** |
|
||||||
* Token拦截器 |
|
||||||
* |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-04-02 15:31 |
|
||||||
*/ |
|
||||||
@Slf4j |
|
||||||
public class FinallyInterceptor implements HandlerInterceptor { |
|
||||||
|
|
||||||
@Resource |
|
||||||
private UserLoginStatusBean userLoginStatusBean; |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private IUserService userService; |
|
||||||
|
|
||||||
private boolean load = true; |
|
||||||
|
|
||||||
private void loadUserLoginStatus() { |
|
||||||
userLoginStatusBean.loadUserLoginStatus(userService.getLoginedUser()); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
|
||||||
if (load) { |
|
||||||
loadUserLoginStatus(); |
|
||||||
load = false; |
|
||||||
} |
|
||||||
boolean pass = false; |
|
||||||
// 允许OPTIONS请求通过
|
|
||||||
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
// 如果不是映射到方法直接通过
|
|
||||||
if (!(handler instanceof HandlerMethod)) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
HandlerMethod handlerMethod = (HandlerMethod) handler; |
|
||||||
Method method = handlerMethod.getMethod(); |
|
||||||
String httpMethod = request.getMethod(); |
|
||||||
SkinEncrypt skinEncrypt = handlerMethod.getMethodAnnotation(SkinEncrypt.class); |
|
||||||
// 检查方法上是否存在SkinLogin注解
|
|
||||||
boolean hasSkinLogin = handlerMethod.getMethodAnnotation(SkinLogin.class) != null; |
|
||||||
// 从请求头中获取 token
|
|
||||||
String token = request.getHeader("jyjc-Token"); |
|
||||||
try { |
|
||||||
/* |
|
||||||
加解密 |
|
||||||
*/ |
|
||||||
// 不拦截get请求
|
|
||||||
if ("GET".equals(httpMethod)) { |
|
||||||
pass = true; |
|
||||||
// 如果是post请求且是json
|
|
||||||
} else if ("POST".equals(httpMethod)) { |
|
||||||
// 如果类型为空就放行
|
|
||||||
if (request.getContentType() == null) { |
|
||||||
pass = true; |
|
||||||
} |
|
||||||
} |
|
||||||
// 跳过使用 @SkinEncrypt 的情况
|
|
||||||
if (skinEncrypt != null) { |
|
||||||
pass = true; |
|
||||||
} |
|
||||||
|
|
||||||
if (!pass) { |
|
||||||
ShaoduoRequestWrapper shaoduoRequestWrapper; |
|
||||||
try { |
|
||||||
shaoduoRequestWrapper = (ShaoduoRequestWrapper) request; |
|
||||||
} catch (Exception e) { |
|
||||||
System.out.printf("request.ClassTypeError: %s%n", request.getClass().getName()); |
|
||||||
return true; |
|
||||||
} |
|
||||||
String sourceParamBody = shaoduoRequestWrapper.getBodyString(); |
|
||||||
String afterBody = EncryptUtils.decrypt(sourceParamBody); |
|
||||||
shaoduoRequestWrapper.setBody(afterBody); |
|
||||||
log.debug(String.format("解密: %s -> %s", sourceParamBody, afterBody)); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
/* token验证 */ |
|
||||||
if (hasSkinLogin) { |
|
||||||
// 跳过使用 @SkinLogin 的情况
|
|
||||||
pass = true; |
|
||||||
} else { |
|
||||||
// 验证token
|
|
||||||
// 检查 token 是否存在并且有效
|
|
||||||
if (token == null) { |
|
||||||
// 没有Token,拒绝请求
|
|
||||||
response.setStatus(40401); |
|
||||||
pass = false; |
|
||||||
} else if (userLoginStatusBean != null) { |
|
||||||
if (!userLoginStatusBean.containsToken(token)) { |
|
||||||
// Token 无效,拒绝请求
|
|
||||||
response.setContentType("application/json"); |
|
||||||
Back<String> back = new Back<String>().setCode(40401).setMessage("Token invalid!"); |
|
||||||
|
|
||||||
// 转换为 JSON 字符串
|
|
||||||
ObjectMapper objectMapper = new ObjectMapper(); |
|
||||||
String responseBody = objectMapper.writeValueAsString(back); |
|
||||||
|
|
||||||
// 输出错误信息到响应中
|
|
||||||
PrintWriter writer = response.getWriter(); |
|
||||||
writer.print(responseBody); |
|
||||||
writer.flush(); |
|
||||||
pass = false; |
|
||||||
} else { |
|
||||||
// token存在, 通过拦截器
|
|
||||||
pass = true; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} catch (Exception e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
return pass; |
|
||||||
} |
|
||||||
} |
|
@ -1,16 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.mapper; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.entity.UserLoginOutDO; |
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|
||||||
|
|
||||||
/** |
|
||||||
* <p> |
|
||||||
* 用户登入登出表 Mapper 接口 |
|
||||||
* </p> |
|
||||||
* |
|
||||||
* @author Soul2 |
|
||||||
* @since 2024-03-29 20:46:42 |
|
||||||
*/ |
|
||||||
public interface UserLoginOutMapper extends BaseMapper<UserLoginOutDO> { |
|
||||||
|
|
||||||
} |
|
@ -1,16 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.mapper; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.entity.UserDO; |
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
|
||||||
|
|
||||||
/** |
|
||||||
* <p> |
|
||||||
* 用户表 Mapper 接口 |
|
||||||
* </p> |
|
||||||
* |
|
||||||
* @author Soul2 |
|
||||||
* @since 2024-03-29 20:46:42 |
|
||||||
*/ |
|
||||||
public interface UserMapper extends BaseMapper<UserDO> { |
|
||||||
|
|
||||||
} |
|
@ -1,71 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.repository; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.dto.UserLoginDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.UserLoginOutPageDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.UserLogoutDTO; |
|
||||||
import cn.soul2.jyjc.admin.entity.UserDO; |
|
||||||
import cn.soul2.jyjc.admin.entity.UserLoginOutDO; |
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
|
||||||
import com.baomidou.mybatisplus.extension.service.IService; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* <p> |
|
||||||
* 用户登入登出表 服务类 |
|
||||||
* </p> |
|
||||||
* |
|
||||||
* @author Soul2 |
|
||||||
* @since 2024-03-29 20:46:42 |
|
||||||
*/ |
|
||||||
public interface IUserLoginOutRepository extends IService<UserLoginOutDO> { |
|
||||||
|
|
||||||
/** |
|
||||||
* 分页查询 |
|
||||||
* |
|
||||||
* @param dto 查询条件 |
|
||||||
* @return {@link IPage}<{@link UserLoginOutDO}> |
|
||||||
*/ |
|
||||||
IPage<UserLoginOutDO> page(UserLoginOutPageDTO dto); |
|
||||||
|
|
||||||
/** |
|
||||||
* 用户登录 |
|
||||||
* |
|
||||||
* @param dto 用户信息 |
|
||||||
* @param user 用户 |
|
||||||
* @return {@link String} |
|
||||||
*/ |
|
||||||
String login(UserLoginDTO dto, UserDO user); |
|
||||||
|
|
||||||
/** |
|
||||||
* 用户登出 |
|
||||||
* |
|
||||||
* @param dto 用户信息 |
|
||||||
* @return {@link String} |
|
||||||
*/ |
|
||||||
String logout(UserLogoutDTO dto); |
|
||||||
|
|
||||||
/** |
|
||||||
* 用户登出 |
|
||||||
* |
|
||||||
* @param userId 用户id |
|
||||||
* @return {@link String} |
|
||||||
*/ |
|
||||||
Boolean logoutByUserId(String userId); |
|
||||||
|
|
||||||
/** |
|
||||||
* 删除目标用户的所有登录记录 |
|
||||||
* |
|
||||||
* @param userId 用户id |
|
||||||
* @return {@link Boolean} |
|
||||||
*/ |
|
||||||
Boolean removeByUserId(String userId); |
|
||||||
|
|
||||||
/** |
|
||||||
* 重建当前登录的用户 |
|
||||||
* |
|
||||||
* @return {@link List}<{@link UserLoginOutDO}> |
|
||||||
*/ |
|
||||||
List<UserLoginOutDO> getLoginedUser(); |
|
||||||
|
|
||||||
} |
|
@ -1,54 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.repository; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.dto.UserPageDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.UserSaveDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.base.UpdateStatusDTO; |
|
||||||
import cn.soul2.jyjc.admin.entity.UserDO; |
|
||||||
import cn.soul2.jyjc.admin.vo.base.VPage; |
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
|
||||||
import com.baomidou.mybatisplus.extension.service.IService; |
|
||||||
|
|
||||||
/** |
|
||||||
* <p> |
|
||||||
* 用户表 服务类 |
|
||||||
* </p> |
|
||||||
* |
|
||||||
* @author Soul2 |
|
||||||
* @since 2024-03-29 20:46:42 |
|
||||||
*/ |
|
||||||
public interface IUserRepository extends IService<UserDO> { |
|
||||||
|
|
||||||
/** |
|
||||||
* 分页查询 |
|
||||||
* |
|
||||||
* @param dto 查询条件 |
|
||||||
* @return {@link VPage}<{@link UserDO}> |
|
||||||
*/ |
|
||||||
IPage<UserDO> page(UserPageDTO dto); |
|
||||||
|
|
||||||
/** |
|
||||||
* 保存或更新 |
|
||||||
* |
|
||||||
* @param dto 有/无id区分更新/新增 |
|
||||||
* @return {@link Boolean} |
|
||||||
*/ |
|
||||||
Boolean saveOrUpdate(UserSaveDTO dto); |
|
||||||
|
|
||||||
/** |
|
||||||
* 更新状态 |
|
||||||
* |
|
||||||
* @param dto 新状态 |
|
||||||
* @return {@link Boolean} |
|
||||||
*/ |
|
||||||
Boolean updateStatus(UpdateStatusDTO dto); |
|
||||||
|
|
||||||
/** |
|
||||||
* 读取指定名字的用户 |
|
||||||
* |
|
||||||
* @param username 用户名 |
|
||||||
* @return {@link UserDO} |
|
||||||
*/ |
|
||||||
UserDO getOneByUsername(String username); |
|
||||||
|
|
||||||
|
|
||||||
} |
|
@ -1,126 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.repository.impl; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.bean.UserLoginStatusBean; |
|
||||||
import cn.soul2.jyjc.admin.dto.UserLoginDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.UserLoginOutPageDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.UserLogoutDTO; |
|
||||||
import cn.soul2.jyjc.admin.entity.UserDO; |
|
||||||
import cn.soul2.jyjc.admin.entity.UserLoginOutDO; |
|
||||||
import cn.soul2.jyjc.admin.mapper.UserLoginOutMapper; |
|
||||||
import cn.soul2.jyjc.admin.repository.IUserLoginOutRepository; |
|
||||||
import cn.soul2.jyjc.admin.utils.base.PageUtils; |
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
|
||||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; |
|
||||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils; |
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|
||||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||||
import org.springframework.stereotype.Service; |
|
||||||
|
|
||||||
import java.time.LocalDateTime; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Comparator; |
|
||||||
import java.util.List; |
|
||||||
import java.util.function.BinaryOperator; |
|
||||||
import java.util.function.Function; |
|
||||||
import java.util.stream.Collectors; |
|
||||||
|
|
||||||
/** |
|
||||||
* <p> |
|
||||||
* 用户登入登出表 服务实现类 |
|
||||||
* </p> |
|
||||||
* |
|
||||||
* @author Soul2 |
|
||||||
* @since 2024-03-29 20:46:42 |
|
||||||
*/ |
|
||||||
@Service |
|
||||||
public class UserLoginOutRepositoryImpl extends ServiceImpl<UserLoginOutMapper, UserLoginOutDO> implements IUserLoginOutRepository { |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private UserLoginStatusBean userLoginStatusBean; |
|
||||||
|
|
||||||
@Override |
|
||||||
public IPage<UserLoginOutDO> page(UserLoginOutPageDTO dto) { |
|
||||||
LambdaQueryWrapper<UserLoginOutDO> query = Wrappers.lambdaQuery(); |
|
||||||
query.eq(StringUtils.isNotBlank(dto.getUserId()), UserLoginOutDO::getUserId, dto.getUserId()) |
|
||||||
.orderByDesc(UserLoginOutDO::getCreatedTime); |
|
||||||
return super.page(PageUtils.build(dto), query); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String login(UserLoginDTO dto, UserDO user) { |
|
||||||
UserLoginOutDO loginOutDO; |
|
||||||
boolean saved; |
|
||||||
LocalDateTime now = LocalDateTime.now(); |
|
||||||
// 判断是否登陆过,在缓存无法读取到目标用户名时即未登录,若登录过则令之前的登录记录失效
|
|
||||||
String token = userLoginStatusBean.getTokenByUsername(dto.getUsername()); |
|
||||||
if (token != null) { |
|
||||||
userLoginStatusBean.logout(token); |
|
||||||
UserLoginOutDO oldLoginOut = super.getById(token); |
|
||||||
oldLoginOut.setLapseTime(now).setLogoutTime(now); |
|
||||||
super.updateById(oldLoginOut); |
|
||||||
} |
|
||||||
loginOutDO = new UserLoginOutDO(); |
|
||||||
loginOutDO.setUserId(user.getId()) |
|
||||||
.setUserName(user.getUsername()) |
|
||||||
.setLoginTime(now) |
|
||||||
.setLapseTime(now.plusHours(2)) |
|
||||||
; |
|
||||||
saved = super.save(loginOutDO); |
|
||||||
if (saved) { |
|
||||||
userLoginStatusBean.login(loginOutDO.getId(), loginOutDO); |
|
||||||
return loginOutDO.getId(); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String logout(UserLogoutDTO dto) { |
|
||||||
// 清除缓存内的登录信息
|
|
||||||
Boolean logout = userLoginStatusBean.logout(dto.getToken()); |
|
||||||
// 保存退出登录的时间
|
|
||||||
LocalDateTime now = LocalDateTime.now(); |
|
||||||
UserLoginOutDO oldLoginOut = super.getById(dto.getToken()); |
|
||||||
oldLoginOut.setLogoutTime(now); |
|
||||||
super.updateById(oldLoginOut); |
|
||||||
|
|
||||||
return logout ? dto.getUsername() : null; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Boolean logoutByUserId(String userId) { |
|
||||||
return userLoginStatusBean.logoutByUserId(userId); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Boolean removeByUserId(String userId) { |
|
||||||
if (org.apache.commons.lang3.StringUtils.isBlank(userId)) { |
|
||||||
return Boolean.TRUE; |
|
||||||
} |
|
||||||
LambdaUpdateWrapper<UserLoginOutDO> update = Wrappers.lambdaUpdate(); |
|
||||||
update.eq(UserLoginOutDO::getUserId, userId); |
|
||||||
return super.remove(update); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public List<UserLoginOutDO> getLoginedUser() { |
|
||||||
LocalDateTime now = LocalDateTime.now(); |
|
||||||
LambdaQueryWrapper<UserLoginOutDO> query = Wrappers.lambdaQuery(); |
|
||||||
query |
|
||||||
.isNull(UserLoginOutDO::getLogoutTime) |
|
||||||
.gt(UserLoginOutDO::getLapseTime, now); |
|
||||||
List<UserLoginOutDO> list = super.list(query); |
|
||||||
if (CollectionUtils.isEmpty(list)) { |
|
||||||
return new ArrayList<>(); |
|
||||||
} |
|
||||||
|
|
||||||
return new ArrayList<>(list |
|
||||||
.stream() |
|
||||||
.collect(Collectors.toMap(UserLoginOutDO::getUserId, |
|
||||||
Function.identity(), |
|
||||||
BinaryOperator.maxBy(Comparator.comparing(UserLoginOutDO::getLoginTime)))) |
|
||||||
.values()); |
|
||||||
} |
|
||||||
} |
|
@ -1,60 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.repository.impl; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.dto.UserPageDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.UserSaveDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.base.UpdateStatusDTO; |
|
||||||
import cn.soul2.jyjc.admin.entity.UserDO; |
|
||||||
import cn.soul2.jyjc.admin.mapper.UserMapper; |
|
||||||
import cn.soul2.jyjc.admin.repository.IUserRepository; |
|
||||||
import cn.soul2.jyjc.admin.utils.base.PageUtils; |
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
|
||||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils; |
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|
||||||
import org.springframework.beans.BeanUtils; |
|
||||||
import org.springframework.stereotype.Service; |
|
||||||
|
|
||||||
/** |
|
||||||
* <p> |
|
||||||
* 用户表 服务实现类 |
|
||||||
* </p> |
|
||||||
* |
|
||||||
* @author Soul2 |
|
||||||
* @since 2024-03-29 20:46:42 |
|
||||||
*/ |
|
||||||
@Service |
|
||||||
public class UserRepositoryImpl extends ServiceImpl<UserMapper, UserDO> implements IUserRepository { |
|
||||||
|
|
||||||
@Override |
|
||||||
public IPage<UserDO> page(UserPageDTO dto) { |
|
||||||
LambdaQueryWrapper<UserDO> query = Wrappers.lambdaQuery(); |
|
||||||
query.eq(dto.getStatus() != null, UserDO::getStatus, dto.getStatus()) |
|
||||||
.like(StringUtils.isNotBlank(dto.getUsername()), UserDO::getUsername, dto.getUsername()) |
|
||||||
.orderByDesc(UserDO::getUpdatedTime); |
|
||||||
return super.page(PageUtils.build(dto), query); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Boolean saveOrUpdate(UserSaveDTO dto) { |
|
||||||
UserDO user = new UserDO(); |
|
||||||
BeanUtils.copyProperties(dto, user); |
|
||||||
return super.saveOrUpdate(user); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Boolean updateStatus(UpdateStatusDTO dto) { |
|
||||||
LambdaUpdateWrapper<UserDO> update = Wrappers.lambdaUpdate(); |
|
||||||
update.set(UserDO::getStatus, dto.getStatus()) |
|
||||||
.eq(UserDO::getId, dto.getId()); |
|
||||||
return super.update(update); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public UserDO getOneByUsername(String username) { |
|
||||||
LambdaQueryWrapper<UserDO> query = Wrappers.lambdaQuery(); |
|
||||||
query.eq(UserDO::getUsername, username); |
|
||||||
return super.getOne(query, false); |
|
||||||
} |
|
||||||
} |
|
@ -1,31 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.service; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.dto.AnswerPageQueryDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.AnswerSubmitDTO; |
|
||||||
import cn.soul2.jyjc.admin.vo.AnswerSheetVO; |
|
||||||
import cn.soul2.jyjc.admin.vo.base.VPage; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-27 14:43 |
|
||||||
*/ |
|
||||||
|
|
||||||
public interface IAnswerService { |
|
||||||
|
|
||||||
/** |
|
||||||
* 提交答卷 |
|
||||||
* |
|
||||||
* @param dto 答卷内容 |
|
||||||
* @return {@link Boolean} |
|
||||||
*/ |
|
||||||
Boolean handleSubmit(AnswerSubmitDTO dto); |
|
||||||
|
|
||||||
/** |
|
||||||
* 分页查询 |
|
||||||
* |
|
||||||
* @param dto 查询条件 |
|
||||||
* @return {@link VPage}<{@link AnswerSheetVO}> |
|
||||||
*/ |
|
||||||
VPage<AnswerSheetVO> page(AnswerPageQueryDTO dto); |
|
||||||
|
|
||||||
} |
|
@ -1,56 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.service; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.dto.UserLoginDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.UserLogoutDTO; |
|
||||||
import cn.soul2.jyjc.admin.entity.UserLoginOutDO; |
|
||||||
import cn.soul2.jyjc.admin.vo.UserVO; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-29 20:47 |
|
||||||
*/ |
|
||||||
|
|
||||||
public interface IUserService { |
|
||||||
|
|
||||||
/** |
|
||||||
* 注册一个用户 |
|
||||||
* |
|
||||||
* @param dto 用户名和密码 |
|
||||||
* @return {@link UserVO} |
|
||||||
*/ |
|
||||||
UserVO register(UserLoginDTO dto); |
|
||||||
|
|
||||||
/** |
|
||||||
* 用户登录 |
|
||||||
* |
|
||||||
* @param dto 用户名和密码 |
|
||||||
* @return {@link UserVO} |
|
||||||
*/ |
|
||||||
UserVO login(UserLoginDTO dto); |
|
||||||
|
|
||||||
/** |
|
||||||
* 用户退出登录 |
|
||||||
* |
|
||||||
* @param dto 登录key |
|
||||||
* @return {@link Boolean} |
|
||||||
*/ |
|
||||||
Boolean logout(UserLogoutDTO dto); |
|
||||||
|
|
||||||
/** |
|
||||||
* 删除用户并退出登录,同时将登录记录一并删除 |
|
||||||
* |
|
||||||
* @param userId 用户id |
|
||||||
* @return {@link Boolean} |
|
||||||
*/ |
|
||||||
Boolean remove(String userId); |
|
||||||
|
|
||||||
/** |
|
||||||
* 重建当前登录的用户 |
|
||||||
* |
|
||||||
* @return {@link List}<{@link UserLoginOutDO}> |
|
||||||
*/ |
|
||||||
List<UserLoginOutDO> getLoginedUser(); |
|
||||||
|
|
||||||
} |
|
@ -1,66 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.service.impl; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.dto.AnswerPageQueryDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.AnswerSubmitDTO; |
|
||||||
import cn.soul2.jyjc.admin.entity.AnswerDetailsDO; |
|
||||||
import cn.soul2.jyjc.admin.entity.AnswerSheetDO; |
|
||||||
import cn.soul2.jyjc.admin.repository.IAnswerDetailsRepository; |
|
||||||
import cn.soul2.jyjc.admin.repository.IAnswerSheetRepository; |
|
||||||
import cn.soul2.jyjc.admin.service.IAnswerService; |
|
||||||
import cn.soul2.jyjc.admin.vo.AnswerSheetVO; |
|
||||||
import cn.soul2.jyjc.admin.vo.base.VPage; |
|
||||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||||
import org.springframework.stereotype.Service; |
|
||||||
import org.springframework.transaction.annotation.Transactional; |
|
||||||
import org.springframework.transaction.interceptor.TransactionAspectSupport; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
import java.util.stream.Collectors; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-27 14:43 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Service |
|
||||||
public class AnswerServiceImpl implements IAnswerService { |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private IAnswerSheetRepository sheetRepository; |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private IAnswerDetailsRepository detailsRepository; |
|
||||||
|
|
||||||
@Override |
|
||||||
@Transactional |
|
||||||
public Boolean handleSubmit(AnswerSubmitDTO dto) { |
|
||||||
AnswerSheetDO sheet = new AnswerSheetDO(); |
|
||||||
sheet.setRespondent(dto.getOpenid()) |
|
||||||
.setQnId(dto.getQnId()) |
|
||||||
.setQrId(dto.getQrId()); |
|
||||||
boolean sheetSaved = sheetRepository.save(sheet); |
|
||||||
if (sheetSaved) { |
|
||||||
List<AnswerDetailsDO> details = dto.getDetails().stream().map(d -> { |
|
||||||
AnswerDetailsDO detail = new AnswerDetailsDO(); |
|
||||||
detail.setAnswerContent(d.getContent()) |
|
||||||
.setAnswerSheetId(sheet.getId()) |
|
||||||
.setSubjectType(d.getSubjectType()) |
|
||||||
.setSubjectId(d.getSubjectId()); |
|
||||||
return detail; |
|
||||||
}).collect(Collectors.toList()); |
|
||||||
boolean detailsSaved = detailsRepository.saveBatch(details); |
|
||||||
if (!detailsSaved) { |
|
||||||
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); |
|
||||||
return Boolean.FALSE; |
|
||||||
} |
|
||||||
} else { |
|
||||||
return Boolean.FALSE; |
|
||||||
} |
|
||||||
return Boolean.TRUE; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public VPage<AnswerSheetVO> page(AnswerPageQueryDTO dto) { |
|
||||||
return sheetRepository.page(dto); |
|
||||||
} |
|
||||||
} |
|
@ -1,95 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.service.impl; |
|
||||||
|
|
||||||
import cn.soul2.jyjc.admin.dto.UserLoginDTO; |
|
||||||
import cn.soul2.jyjc.admin.dto.UserLogoutDTO; |
|
||||||
import cn.soul2.jyjc.admin.entity.UserDO; |
|
||||||
import cn.soul2.jyjc.admin.entity.UserLoginOutDO; |
|
||||||
import cn.soul2.jyjc.admin.repository.IUserLoginOutRepository; |
|
||||||
import cn.soul2.jyjc.admin.repository.IUserRepository; |
|
||||||
import cn.soul2.jyjc.admin.service.IUserService; |
|
||||||
import cn.soul2.jyjc.admin.utils.Md5Utils; |
|
||||||
import cn.soul2.jyjc.admin.vo.UserVO; |
|
||||||
import org.springframework.beans.BeanUtils; |
|
||||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||||
import org.springframework.stereotype.Service; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-29 20:47 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Service |
|
||||||
public class UserServiceImpl implements IUserService { |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private IUserRepository userRepository; |
|
||||||
|
|
||||||
@Autowired |
|
||||||
private IUserLoginOutRepository loginOutRepository; |
|
||||||
|
|
||||||
@Override |
|
||||||
public UserVO register(UserLoginDTO dto) { |
|
||||||
UserVO vo = new UserVO(); |
|
||||||
if (userRepository.getOneByUsername(dto.getUsername()) == null) { |
|
||||||
UserDO user = new UserDO(); |
|
||||||
user.setUsername(dto.getUsername()) |
|
||||||
.setPassword(Md5Utils.md5(dto.getPassword())); |
|
||||||
boolean saved = userRepository.save(user); |
|
||||||
if (!saved) { |
|
||||||
vo.setLoginFail("注册失败!"); |
|
||||||
} else { |
|
||||||
String loginKey = loginOutRepository.login(dto, user); |
|
||||||
if (loginKey != null) { |
|
||||||
BeanUtils.copyProperties(user, vo); |
|
||||||
vo.setToken(loginKey); |
|
||||||
} else { |
|
||||||
vo.setLoginFail("注册成功但登录失败!"); |
|
||||||
} |
|
||||||
} |
|
||||||
} else { |
|
||||||
vo.setLoginFail("用户名已存在!"); |
|
||||||
} |
|
||||||
return vo; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public UserVO login(UserLoginDTO dto) { |
|
||||||
UserVO vo = new UserVO(); |
|
||||||
UserDO user = userRepository.getOneByUsername(dto.getUsername()); |
|
||||||
if (user != null) { |
|
||||||
if (Md5Utils.verify(user.getPassword(), dto.getPassword())) { |
|
||||||
String loginKey = loginOutRepository.login(dto, user); |
|
||||||
if (loginKey != null) { |
|
||||||
BeanUtils.copyProperties(user, vo); |
|
||||||
vo.setToken(loginKey); |
|
||||||
} else { |
|
||||||
vo.setLoginFail("登录失败!"); |
|
||||||
} |
|
||||||
} else { |
|
||||||
vo.setLoginFail("密码错误!"); |
|
||||||
} |
|
||||||
} else { |
|
||||||
vo.setLoginFail("该用户尚未注册!"); |
|
||||||
} |
|
||||||
return vo; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Boolean logout(UserLogoutDTO dto) { |
|
||||||
return loginOutRepository.logout(dto) != null; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Boolean remove(String userId) { |
|
||||||
loginOutRepository.logoutByUserId(userId); |
|
||||||
loginOutRepository.removeByUserId(userId); |
|
||||||
return userRepository.removeById(userId); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public List<UserLoginOutDO> getLoginedUser() { |
|
||||||
return loginOutRepository.getLoginedUser(); |
|
||||||
} |
|
||||||
} |
|
@ -1,48 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.utils; |
|
||||||
|
|
||||||
import javax.crypto.Cipher; |
|
||||||
import javax.crypto.spec.SecretKeySpec; |
|
||||||
import java.util.Base64; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-30 14:02 |
|
||||||
*/ |
|
||||||
|
|
||||||
public class AesUtils { |
|
||||||
|
|
||||||
private static final String AES_KEY = "98478f8a45887eda446501bcb44010520c3f53c7b45ff36215e86ce4f049b0f2"; |
|
||||||
|
|
||||||
private static final String AES_ALGORITHM = "AES"; |
|
||||||
|
|
||||||
private static SecretKeySpec generateKey(String key) { |
|
||||||
return new SecretKeySpec(key.getBytes(), AES_ALGORITHM); |
|
||||||
} |
|
||||||
|
|
||||||
public static String encrypt(String source) throws Exception { |
|
||||||
return encrypt(source, AES_KEY); |
|
||||||
} |
|
||||||
|
|
||||||
public static String decrypt(String encrypted) throws Exception { |
|
||||||
return decrypt(encrypted, AES_KEY); |
|
||||||
} |
|
||||||
|
|
||||||
public static String encrypt(String source, String key) throws Exception { |
|
||||||
Cipher cipher = Cipher.getInstance(AES_ALGORITHM); |
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, generateKey(key)); |
|
||||||
byte[] encryptedBytes = cipher.doFinal(source.getBytes()); |
|
||||||
return Base64.getEncoder().encodeToString(encryptedBytes); |
|
||||||
} |
|
||||||
|
|
||||||
public static String decrypt(String encrypted, String key) throws Exception { |
|
||||||
Cipher cipher = Cipher.getInstance(AES_ALGORITHM); |
|
||||||
cipher.init(Cipher.DECRYPT_MODE, generateKey(key)); |
|
||||||
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encrypted)); |
|
||||||
return new String(decryptedBytes); |
|
||||||
} |
|
||||||
|
|
||||||
public static void main(String[] args) { |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
} |
|
@ -1,132 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.utils; |
|
||||||
|
|
||||||
import org.apache.tomcat.util.codec.binary.Base64; |
|
||||||
|
|
||||||
import javax.crypto.Cipher; |
|
||||||
import javax.crypto.KeyGenerator; |
|
||||||
import javax.crypto.spec.SecretKeySpec; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-04-08 15:00 |
|
||||||
* <p>照抄自 <a href="https://blog.csdn.net/shaoduo/article/details/122322578">Shao duo</a></p> |
|
||||||
*/ |
|
||||||
|
|
||||||
public class EncryptUtils { |
|
||||||
|
|
||||||
private static final String KEY = "620b8d3c3be1e725"; |
|
||||||
|
|
||||||
//参数分别代表 算法名称/加密模式/数据填充方式
|
|
||||||
private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding"; |
|
||||||
|
|
||||||
/** |
|
||||||
* 加密 |
|
||||||
* |
|
||||||
* @param content 加密的字符串 |
|
||||||
* @param encryptKey key值 |
|
||||||
* @return {@link String} |
|
||||||
*/ |
|
||||||
public static String encrypt(String content, String encryptKey) throws Exception { |
|
||||||
KeyGenerator kgen = KeyGenerator.getInstance("AES"); |
|
||||||
kgen.init(128); |
|
||||||
Cipher cipher = Cipher.getInstance(ALGORITHMSTR); |
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES")); |
|
||||||
byte[] b = cipher.doFinal(content.getBytes("utf-8")); |
|
||||||
// 采用base64算法进行转码,避免出现中文乱码
|
|
||||||
return Base64.encodeBase64String(b); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 解密 |
|
||||||
* |
|
||||||
* @param encryptStr 解密的字符串 |
|
||||||
* @param decryptKey 解密的key值 |
|
||||||
* @return {@link String} |
|
||||||
*/ |
|
||||||
public static String decrypt(String encryptStr, String decryptKey) throws Exception { |
|
||||||
KeyGenerator kgen = KeyGenerator.getInstance("AES"); |
|
||||||
kgen.init(128); |
|
||||||
Cipher cipher = Cipher.getInstance(ALGORITHMSTR); |
|
||||||
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes("utf-8"), "AES")); |
|
||||||
// 采用base64算法进行转码,避免出现中文乱码
|
|
||||||
|
|
||||||
//byte[] b = hex2Bytes(encryptStr) ;
|
|
||||||
byte[] encryptBytes = Base64.decodeBase64(encryptStr); |
|
||||||
byte[] decryptBytes = cipher.doFinal(encryptBytes); |
|
||||||
return new String(decryptBytes); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param content 加密的字符串 |
|
||||||
* @return {@link String} |
|
||||||
*/ |
|
||||||
public static String encrypt(String content) throws Exception { |
|
||||||
return encrypt(content, KEY); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param encryptStr 解密的字符串 |
|
||||||
* @return {@link String} |
|
||||||
*/ |
|
||||||
public static String decrypt(String encryptStr) throws Exception { |
|
||||||
return decrypt(encryptStr, KEY); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/* public static void main(String[] args) throws Exception { |
|
||||||
Map map=new HashMap<String,String>(); |
|
||||||
map.put("key","value"); |
|
||||||
map.put("中文","汉字"); |
|
||||||
String content = JSONObject.toJSONString(map); |
|
||||||
System.out.println("加密前:" + content); |
|
||||||
String encrypt = encrypt(content, KEY); |
|
||||||
System.out.println("加密后:" + encrypt); |
|
||||||
String decrypt = decrypt(encrypt, KEY); |
|
||||||
System.out.println("解密后:" + decrypt); |
|
||||||
}*/ |
|
||||||
|
|
||||||
/** |
|
||||||
* byte数组 转换成 16进制小写字符串 |
|
||||||
*/ |
|
||||||
public static String bytes2Hex(byte[] bytes) { |
|
||||||
if (bytes == null || bytes.length == 0) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
StringBuilder hex = new StringBuilder(); |
|
||||||
|
|
||||||
for (byte b : bytes) { |
|
||||||
hex.append(HEXES[(b >> 4) & 0x0F]); |
|
||||||
hex.append(HEXES[b & 0x0F]); |
|
||||||
} |
|
||||||
|
|
||||||
return hex.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 16进制字符串 转换为对应的 byte数组 |
|
||||||
*/ |
|
||||||
public static byte[] hex2Bytes(String hex) { |
|
||||||
if (hex == null || hex.length() == 0) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
char[] hexChars = hex.toCharArray(); |
|
||||||
// 如果 hex 中的字符不是偶数个, 则忽略最后一个
|
|
||||||
byte[] bytes = new byte[hexChars.length / 2]; |
|
||||||
|
|
||||||
for (int i = 0; i < bytes.length; i++) { |
|
||||||
bytes[i] = (byte) Integer.parseInt("" + hexChars[i * 2] + hexChars[i * 2 + 1], 16); |
|
||||||
} |
|
||||||
|
|
||||||
return bytes; |
|
||||||
} |
|
||||||
|
|
||||||
private static final char[] HEXES = { |
|
||||||
'0', '1', '2', '3', |
|
||||||
'4', '5', '6', '7', |
|
||||||
'8', '9', 'a', 'b', |
|
||||||
'c', 'd', 'e', 'f' |
|
||||||
}; |
|
||||||
|
|
||||||
} |
|
@ -1,33 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.utils; |
|
||||||
|
|
||||||
import org.springframework.util.DigestUtils; |
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets; |
|
||||||
import java.util.Objects; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author fuzongyao |
|
||||||
* @date 2021/10/14 11:19 |
|
||||||
* @since 1.0 |
|
||||||
*/ |
|
||||||
public class Md5Utils { |
|
||||||
|
|
||||||
/** |
|
||||||
* 加盐 |
|
||||||
*/ |
|
||||||
private static final String SALT = "4v6dKAOn+tEiVH58/XKeUw=="; |
|
||||||
|
|
||||||
public static String md5(String body) { |
|
||||||
body += SALT; |
|
||||||
return DigestUtils.md5DigestAsHex(body.getBytes(StandardCharsets.UTF_8)).toUpperCase(); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean verify(String md5, String body) { |
|
||||||
return Objects.equals(md5, md5(body)); |
|
||||||
} |
|
||||||
|
|
||||||
public static void main(String[] args) { |
|
||||||
System.out.println(md5("123456")); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,35 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.utils; |
|
||||||
|
|
||||||
import java.security.SecureRandom; |
|
||||||
import java.util.Base64; |
|
||||||
|
|
||||||
/** |
|
||||||
* 盐值生成 |
|
||||||
* |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-30 14:30 |
|
||||||
*/ |
|
||||||
|
|
||||||
public class SaltUtils { |
|
||||||
|
|
||||||
/** |
|
||||||
* 生成指定长度的盐值 |
|
||||||
* |
|
||||||
* @param length 盐值长度 |
|
||||||
* @return {@link String} |
|
||||||
*/ |
|
||||||
public static String generateSalt(int length) { |
|
||||||
SecureRandom random = new SecureRandom(); |
|
||||||
byte[] salt = new byte[length]; |
|
||||||
random.nextBytes(salt); |
|
||||||
return Base64.getEncoder().encodeToString(salt); |
|
||||||
} |
|
||||||
|
|
||||||
public static void main(String[] args) { |
|
||||||
// 设置盐值长度
|
|
||||||
int saltLength = 16; |
|
||||||
String salt = generateSalt(saltLength); |
|
||||||
System.out.println("Generated Salt: " + salt); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,32 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.vo; |
|
||||||
|
|
||||||
import lombok.Data; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-05-10 12:46 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Data |
|
||||||
@Accessors(chain = true) |
|
||||||
public class AnswerPageVO { |
|
||||||
|
|
||||||
/** |
|
||||||
* qnId |
|
||||||
*/ |
|
||||||
private String qnId; |
|
||||||
|
|
||||||
/** |
|
||||||
* qnName |
|
||||||
*/ |
|
||||||
private String qnName; |
|
||||||
|
|
||||||
/** |
|
||||||
* sheets |
|
||||||
*/ |
|
||||||
private List<AnswerSheetVO> sheets; |
|
||||||
|
|
||||||
} |
|
@ -1,38 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.vo; |
|
||||||
|
|
||||||
import lombok.Data; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-03-30 14:40 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Data |
|
||||||
@Accessors(chain = true) |
|
||||||
public class UserVO { |
|
||||||
|
|
||||||
/** |
|
||||||
* username |
|
||||||
*/ |
|
||||||
private String username; |
|
||||||
|
|
||||||
/** |
|
||||||
* token |
|
||||||
* 其实就是'UserLoginOut'表的id |
|
||||||
*/ |
|
||||||
private String token; |
|
||||||
|
|
||||||
/** |
|
||||||
* 权限等级 |
|
||||||
*/ |
|
||||||
private String authorityLevel; |
|
||||||
|
|
||||||
/** |
|
||||||
* 状态;0(默认):正常;4:封号;9:异常; |
|
||||||
*/ |
|
||||||
private Integer status; |
|
||||||
|
|
||||||
private String loginFail; |
|
||||||
|
|
||||||
} |
|
@ -1,34 +0,0 @@ |
|||||||
package cn.soul2.jyjc.admin.vo.base; |
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat; |
|
||||||
import lombok.Data; |
|
||||||
import lombok.experimental.Accessors; |
|
||||||
|
|
||||||
import java.time.LocalDateTime; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Soul2 |
|
||||||
* @date 2024-05-10 15:07 |
|
||||||
*/ |
|
||||||
|
|
||||||
@Data |
|
||||||
@Accessors(chain = true) |
|
||||||
public class OptionsVO { |
|
||||||
|
|
||||||
/** |
|
||||||
* code |
|
||||||
*/ |
|
||||||
private String code; |
|
||||||
|
|
||||||
/** |
|
||||||
* label |
|
||||||
*/ |
|
||||||
private String label; |
|
||||||
|
|
||||||
/** |
|
||||||
* date time |
|
||||||
*/ |
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|
||||||
private LocalDateTime time; |
|
||||||
|
|
||||||
} |
|
@ -1,127 +0,0 @@ |
|||||||
<?xml version="1.0" encoding="UTF-8"?> |
|
||||||
<configuration scan="true" scanPeriod="10 seconds"> |
|
||||||
|
|
||||||
<!--<include resource="org/springframework/boot/logging/logback/base.xml" />--> |
|
||||||
|
|
||||||
<contextName>logback</contextName> |
|
||||||
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 --> |
|
||||||
<!-- <property name="log.path" value=".logs/"/>--> |
|
||||||
<springProperty scope="context" name="log.path" source="logging.path" defaultValue="./logs/"/> |
|
||||||
<property name="log.pattern" |
|
||||||
value="%cyan(%d{HH:mm:ss}) %green(%-5level) %blue(%logger{50}) - %boldMagenta(%msg) \t\t ---- %yellow([%thread] %d{yyyy-MM-dd HH:mm:ss.SSS}) %n" |
|
||||||
/> |
|
||||||
<property name="debug.path" value="${log.path}/%d{yyyyMM,aux}/%d{dd,aux}/debug-%d{yyyyMMdd}.%i.log.gz"/> |
|
||||||
<property name="info.path" value="${log.path}/%d{yyyyMM,aux}/%d{dd,aux}/info-%d{yyyyMMdd}.%i.log.gz"/> |
|
||||||
<property name="error.path" value="${log.path}/%d{yyyyMM,aux}/%d{dd,aux}/error-%d{yyyyMMdd}.%i.log.gz"/> |
|
||||||
|
|
||||||
<!--输出到控制台--> |
|
||||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> |
|
||||||
<!-- 控制台输出的日志级别是大于或等于此级别的日志信息 --> |
|
||||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> |
|
||||||
<level>DEBUG</level> |
|
||||||
</filter> |
|
||||||
<!--日志文件输出格式与字符集--> |
|
||||||
<encoder> |
|
||||||
<Pattern>${log.pattern}</Pattern> |
|
||||||
<charset>UTF-8</charset> |
|
||||||
</encoder> |
|
||||||
</appender> |
|
||||||
|
|
||||||
<!--输出到文件--> |
|
||||||
<!-- 时间滚动输出 level为 DEBUG 日志 --> |
|
||||||
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
|
||||||
<!-- 正在记录的日志文件的路径及文件名 --> |
|
||||||
<file>${log.path}/debug.log</file> |
|
||||||
<!--日志文件输出格式与字符集--> |
|
||||||
<encoder> |
|
||||||
<pattern>${log.pattern}</pattern> |
|
||||||
<charset>UTF-8</charset> |
|
||||||
</encoder> |
|
||||||
<!-- 日志记录器的滚动策略,按日期,按大小记录 --> |
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
|
||||||
<!-- 日志归档 --> |
|
||||||
<fileNamePattern>${debug.path}</fileNamePattern> |
|
||||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> |
|
||||||
<maxFileSize>10MB</maxFileSize> |
|
||||||
</timeBasedFileNamingAndTriggeringPolicy> |
|
||||||
<!--日志文件保留天数--> |
|
||||||
<maxHistory>7</maxHistory> |
|
||||||
</rollingPolicy> |
|
||||||
<!-- 此日志文件记录debug级别以上的 --> |
|
||||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> |
|
||||||
<level>DEBUG</level> |
|
||||||
</filter> |
|
||||||
</appender> |
|
||||||
|
|
||||||
<!-- 时间滚动输出 level为 INFO 日志 --> |
|
||||||
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
|
||||||
<!-- 正在记录的日志文件的路径及文件名 --> |
|
||||||
<file>${log.path}/info.log</file> |
|
||||||
<!--日志文件输出格式--> |
|
||||||
<encoder> |
|
||||||
<pattern>${log.pattern}</pattern> |
|
||||||
<charset>UTF-8</charset> |
|
||||||
</encoder> |
|
||||||
<!-- 日志记录器的滚动策略,按日期,按大小记录 --> |
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
|
||||||
<!-- 每天日志归档路径以及格式 --> |
|
||||||
<fileNamePattern>${info.path}</fileNamePattern> |
|
||||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> |
|
||||||
<maxFileSize>100MB</maxFileSize> |
|
||||||
</timeBasedFileNamingAndTriggeringPolicy> |
|
||||||
<!--日志文件保留天数--> |
|
||||||
<maxHistory>60</maxHistory> |
|
||||||
</rollingPolicy> |
|
||||||
<!-- 此日志文件记录info级别以上的 --> |
|
||||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> |
|
||||||
<level>INFO</level> |
|
||||||
</filter> |
|
||||||
</appender> |
|
||||||
|
|
||||||
<!-- 时间滚动输出 level为 ERROR 日志 --> |
|
||||||
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
|
||||||
<!-- 正在记录的日志文件的路径及文件名 --> |
|
||||||
<file>${log.path}/error.log</file> |
|
||||||
<!--日志文件输出格式--> |
|
||||||
<encoder> |
|
||||||
<pattern>${log.pattern}</pattern> |
|
||||||
<charset>UTF-8</charset> <!-- 此处设置字符集 --> |
|
||||||
</encoder> |
|
||||||
<!-- 日志记录器的滚动策略,按日期,按大小记录 --> |
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
|
||||||
<fileNamePattern>${error.path}</fileNamePattern> |
|
||||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> |
|
||||||
<maxFileSize>10MB</maxFileSize> |
|
||||||
</timeBasedFileNamingAndTriggeringPolicy> |
|
||||||
<!--日志文件保留天数--> |
|
||||||
<maxHistory>60</maxHistory> |
|
||||||
</rollingPolicy> |
|
||||||
<!-- 此日志文件记录error级别以上的 --> |
|
||||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> |
|
||||||
<level>ERROR</level> |
|
||||||
</filter> |
|
||||||
</appender> |
|
||||||
|
|
||||||
<!--开发环境:打印控制台--> |
|
||||||
<springProfile name="local,dev,test"> |
|
||||||
<logger level="DEBUG" additivity="false" name="cn.soul2"> |
|
||||||
<appender-ref ref="CONSOLE"/> |
|
||||||
<appender-ref ref="DEBUG_FILE"/> |
|
||||||
<appender-ref ref="INFO_FILE"/> |
|
||||||
<appender-ref ref="ERROR_FILE"/> |
|
||||||
</logger> |
|
||||||
<root level="INFO"> |
|
||||||
<appender-ref ref="CONSOLE"/> |
|
||||||
<appender-ref ref="INFO_FILE"/> |
|
||||||
<appender-ref ref="ERROR_FILE"/> |
|
||||||
</root> |
|
||||||
</springProfile> |
|
||||||
|
|
||||||
<!--生产环境:输出到文件--> |
|
||||||
<springProfile name="pre,prod,prod-yun"> |
|
||||||
<root level="INFO"> |
|
||||||
<appender-ref ref="INFO_FILE"/> |
|
||||||
<appender-ref ref="ERROR_FILE"/> |
|
||||||
</root> |
|
||||||
</springProfile> |
|
||||||
</configuration> |
|
Loading…
Reference in new issue