generated from wenxin/springboot-template
新增权限拦截,异常发送邮箱
This commit is contained in:
parent
12e8ddf9f4
commit
59f4c176ec
16
pom.xml
16
pom.xml
@ -18,12 +18,26 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.jodah</groupId>
|
||||||
|
<artifactId>expiringmap</artifactId>
|
||||||
|
<version>0.5.11</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>mysql</groupId>
|
<groupId>mysql</groupId>
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
@ -3,9 +3,11 @@ package com.linxyun.homework;
|
|||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@MapperScan("com.linxyun.homework.mapper")
|
@MapperScan("com.linxyun.homework.mapper")
|
||||||
|
@EnableConfigurationProperties
|
||||||
public class HomeworkApplication {
|
public class HomeworkApplication {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(HomeworkApplication.class, args);
|
SpringApplication.run(HomeworkApplication.class, args);
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package com.linxyun.homework.bot;
|
package com.linxyun.homework.bot;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.linxyun.homework.bot.handler.MyEventHandler;
|
import com.linxyun.homework.bot.handler.AppointGroupEventHandler;
|
||||||
|
import com.linxyun.homework.bot.handler.BotStatusHandler;
|
||||||
import com.linxyun.homework.domain.dto.ClassGroupTeacher;
|
import com.linxyun.homework.domain.dto.ClassGroupTeacher;
|
||||||
import com.linxyun.homework.domain.po.Class;;
|
import com.linxyun.homework.domain.po.Class;
|
||||||
import com.linxyun.homework.mapper.ClassMapper;
|
import com.linxyun.homework.mapper.ClassMapper;
|
||||||
import com.linxyun.homework.mapper.ClassQqGroupTeacherMapper;
|
import com.linxyun.homework.mapper.ClassQqGroupTeacherMapper;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -24,6 +25,8 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@ -37,7 +40,10 @@ public class MyBot implements ApplicationRunner {
|
|||||||
private final ClassQqGroupTeacherMapper classQqGroupTeacherMapper;
|
private final ClassQqGroupTeacherMapper classQqGroupTeacherMapper;
|
||||||
|
|
||||||
private final ClassMapper classMapper;
|
private final ClassMapper classMapper;
|
||||||
private final MyEventHandler myEventHandler;
|
|
||||||
|
private final AppointGroupEventHandler appointGroupEventHandler;
|
||||||
|
|
||||||
|
private final BotStatusHandler botStatusHandler;
|
||||||
|
|
||||||
/* 登录QQ */
|
/* 登录QQ */
|
||||||
@Value("${mirai.bot.qq}")
|
@Value("${mirai.bot.qq}")
|
||||||
@ -100,7 +106,10 @@ public class MyBot implements ApplicationRunner {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
).registerListenerHost(myEventHandler);
|
).registerListenerHost(appointGroupEventHandler);
|
||||||
|
eventChannel
|
||||||
|
.filterIsInstance(BotEvent.class)
|
||||||
|
.registerListenerHost(botStatusHandler);
|
||||||
new Thread(bot::join).start();
|
new Thread(bot::join).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ import java.util.UUID;
|
|||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class MyEventHandler extends SimpleListenerHost {
|
public class AppointGroupEventHandler extends SimpleListenerHost {
|
||||||
private final FileUtils fileUtils;
|
private final FileUtils fileUtils;
|
||||||
private final TeacherQqMsgsMapper teacherQqMsgsMapper;
|
private final TeacherQqMsgsMapper teacherQqMsgsMapper;
|
||||||
@Value("${mirai.bot.listening-type}")
|
@Value("${mirai.bot.listening-type}")
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.linxyun.homework.bot.handler;
|
||||||
|
|
||||||
|
import com.linxyun.homework.utils.EmailUtils;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.mamoe.mirai.event.EventHandler;
|
||||||
|
import net.mamoe.mirai.event.SimpleListenerHost;
|
||||||
|
import net.mamoe.mirai.event.events.BotOfflineEvent;
|
||||||
|
import net.mamoe.mirai.event.events.BotOnlineEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class BotStatusHandler extends SimpleListenerHost {
|
||||||
|
|
||||||
|
private final EmailUtils emailUtils;
|
||||||
|
|
||||||
|
// 机器人上线通知
|
||||||
|
@EventHandler
|
||||||
|
public void onMessage(@NotNull BotOnlineEvent event) {
|
||||||
|
log.info("机器人上线通知:{}", event);
|
||||||
|
emailUtils.sendEmail("机器人上线通知", "机器人" + event.getBot().getId() + "上线了");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 机器人离线通知
|
||||||
|
@EventHandler
|
||||||
|
public void onMessage(@NotNull BotOfflineEvent event) {
|
||||||
|
log.error("机器人离线通知:{}", event);
|
||||||
|
if (event instanceof BotOfflineEvent.Active) {
|
||||||
|
emailUtils.sendEmail("机器人离线通知", "机器人" + event.getBot().getId() + ":主动离线了");
|
||||||
|
}
|
||||||
|
if (event instanceof BotOfflineEvent.Force) {
|
||||||
|
emailUtils.sendEmail("机器人离线通知", "机器人" + event.getBot().getId() + ":被挤下线了");
|
||||||
|
}
|
||||||
|
if (event instanceof BotOfflineEvent.Dropped) {
|
||||||
|
emailUtils.sendEmail("机器人离线通知", "机器人" + event.getBot().getId() + ":被服务器断开或因网络问题而掉线了");
|
||||||
|
}
|
||||||
|
if (event instanceof BotOfflineEvent.RequireReconnect) {
|
||||||
|
emailUtils.sendEmail("机器人离线通知", "机器人" + event.getBot().getId() + ":服务器主动要求更换另一个服务器");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -68,7 +68,9 @@ public enum ErrorCode {
|
|||||||
// 验证码验证失败
|
// 验证码验证失败
|
||||||
VERIFICATION_CODE_FAIL("1024", "验证码验证失败"),
|
VERIFICATION_CODE_FAIL("1024", "验证码验证失败"),
|
||||||
|
|
||||||
// 用户组已经存在
|
USER_NO_AUTHORITY("1025", "用户没有权限"),
|
||||||
|
|
||||||
|
// 用户组已经存在
|
||||||
USER_GROUP_ALREADY_EXISTS("1030", "用户组已经存在"),
|
USER_GROUP_ALREADY_EXISTS("1030", "用户组已经存在"),
|
||||||
|
|
||||||
// 用户组不存在
|
// 用户组不存在
|
||||||
|
@ -1,24 +1,45 @@
|
|||||||
package com.linxyun.homework.common.exception;
|
package com.linxyun.homework.common.exception;
|
||||||
|
|
||||||
|
import com.linxyun.homework.common.properties.LinxyunProperties;
|
||||||
import com.linxyun.homework.utils.EmailUtils;
|
import com.linxyun.homework.utils.EmailUtils;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ControllerAdvice
|
@ControllerAdvice
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class GlobalExceptionHandler {
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
@Resource
|
private final EmailUtils emailUtils;
|
||||||
private EmailUtils emailUtils;
|
|
||||||
|
private final LinxyunProperties linxyunProperties;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ExceptionHandler(value = Exception.class)
|
@ExceptionHandler(value = Exception.class)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public void exceptionHandler(Exception e) {
|
public void exceptionHandler(Exception e) {
|
||||||
emailUtils.sendEmail("异常捕获", e.getMessage());
|
String subject = "系统异常-" + linxyunProperties.getProject();
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
e.printStackTrace(new PrintWriter(stringWriter));
|
||||||
|
String stackTrace = stringWriter.toString();
|
||||||
|
String emailContent = String.format(
|
||||||
|
"异常捕获:\n消息: %s\n原因: %s\n堆栈信息:\n%s",
|
||||||
|
e.getMessage(),
|
||||||
|
e.getCause(),
|
||||||
|
stackTrace
|
||||||
|
);
|
||||||
|
emailUtils.sendEmail(subject, emailContent);
|
||||||
|
|
||||||
|
// 记录日志
|
||||||
log.error("ExceptionHandler exception: {}", e.getMessage());
|
log.error("ExceptionHandler exception: {}", e.getMessage());
|
||||||
|
log.error("完整堆栈信息: {}", stackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package com.linxyun.homework.common.properties;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "linxyun")
|
||||||
|
@Validated
|
||||||
|
public class LinxyunProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* url
|
||||||
|
*/
|
||||||
|
private String url = "http://www.linxyun.com";
|
||||||
|
/**
|
||||||
|
* 企业编码
|
||||||
|
*/
|
||||||
|
@NotNull(message = "The 'entCode' property is mandatory")
|
||||||
|
private String entCode;
|
||||||
|
/**
|
||||||
|
* 项目名称
|
||||||
|
*/
|
||||||
|
@NotNull(message = "The 'project' property is mandatory")
|
||||||
|
private String project;
|
||||||
|
/**
|
||||||
|
* 角色权限
|
||||||
|
*/
|
||||||
|
private Map<String, List<String>> role = Map.of();
|
||||||
|
/**
|
||||||
|
* 白名单
|
||||||
|
*/
|
||||||
|
private List<String> whiteList = List.of();
|
||||||
|
/**
|
||||||
|
* 上传配置
|
||||||
|
*/
|
||||||
|
private Upload upload = new Upload();
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class Upload {
|
||||||
|
private Float imgQuality = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Value("${server.servlet.context-path}")
|
||||||
|
private String contextPath;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
// 解决 springboot 设置 context-path,导致权限路由验证失效
|
||||||
|
if (contextPath != null && !contextPath.isEmpty()) {
|
||||||
|
for (String key : role.keySet()) {
|
||||||
|
List<String> paths = role.get(key);
|
||||||
|
for (int i = 0; i < paths.size(); i++) {
|
||||||
|
String path = paths.get(i);
|
||||||
|
if (!path.startsWith(contextPath)) {
|
||||||
|
paths.set(i, contextPath + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.linxyun.homework.config;
|
||||||
|
|
||||||
|
|
||||||
|
import com.linxyun.homework.domain.dto.UserAuth;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class SecurityConfig {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,25 @@
|
|||||||
package com.linxyun.homework.config;
|
package com.linxyun.homework.config;
|
||||||
|
|
||||||
|
import com.linxyun.homework.common.properties.LinxyunProperties;
|
||||||
|
import com.linxyun.homework.interceptor.SecurityInterceptor;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
@Slf4j
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class WebConfig implements WebMvcConfigurer {
|
public class WebConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
private final LinxyunProperties linxyunProperties;
|
||||||
|
|
||||||
|
private final SecurityInterceptor securityInterceptor;
|
||||||
|
|
||||||
// 全局跨域
|
// 全局跨域
|
||||||
@Override
|
@Override
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
@ -16,4 +30,20 @@ public class WebConfig implements WebMvcConfigurer {
|
|||||||
.maxAge(3600)
|
.maxAge(3600)
|
||||||
.allowedHeaders("*");
|
.allowedHeaders("*");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加拦截器
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(@NotNull InterceptorRegistry registry) {
|
||||||
|
List<String> whiteList = linxyunProperties.getWhiteList();
|
||||||
|
// 添加默认的静态资源路径排除
|
||||||
|
whiteList.add("/static/**");
|
||||||
|
whiteList.add("/public/**");
|
||||||
|
whiteList.add("/resources/**");
|
||||||
|
whiteList.add("/META-INF/resources/**");
|
||||||
|
whiteList.add("/webjars/**");
|
||||||
|
log.info("白名单:{}", whiteList);
|
||||||
|
registry.addInterceptor(securityInterceptor)
|
||||||
|
.excludePathPatterns(whiteList)
|
||||||
|
.addPathPatterns("/**");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package com.linxyun.homework.domain.dto;
|
package com.linxyun.homework.domain.dto;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@ToString
|
||||||
public class ClassGroupTeacher {
|
public class ClassGroupTeacher {
|
||||||
private String teacherGroupId;
|
private String teacherGroupId;
|
||||||
private String teacherNickname;
|
private String teacherNickname;
|
||||||
|
17
src/main/java/com/linxyun/homework/domain/dto/UserAuth.java
Normal file
17
src/main/java/com/linxyun/homework/domain/dto/UserAuth.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.linxyun.homework.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UserAuth {
|
||||||
|
// "ContainerID\": \"200\",\"EntCode\": \"57\",\"LoginEntCode\": \"8\",\"LoginIP\": \"\",\"LoginNodeID\": \"16\",\"LoginTime\": \"1733380482\",\"UserID\": \"18115602676\",\"UserName\": \"\",\"UserRoles\": \"1101\"
|
||||||
|
private String ContainerID;
|
||||||
|
private String EntCode;
|
||||||
|
private String LoginEntCode;
|
||||||
|
private String LoginIP;
|
||||||
|
private String LoginNodeID;
|
||||||
|
private String LoginTime;
|
||||||
|
private String UserID;
|
||||||
|
private String UserName;
|
||||||
|
private String UserRoles;
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
package com.linxyun.homework.interceptor;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.linxyun.homework.common.entity.Result;
|
||||||
|
import com.linxyun.homework.common.enums.ErrorCode;
|
||||||
|
import com.linxyun.homework.common.properties.LinxyunProperties;
|
||||||
|
import com.linxyun.homework.domain.dto.UserAuth;
|
||||||
|
import com.linxyun.homework.utils.LinxyunUtils;
|
||||||
|
import com.linxyun.homework.utils.StringUtils;
|
||||||
|
import com.linxyun.homework.utils.URLUtils;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SecurityInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
private final LinxyunProperties linxyunProperties;
|
||||||
|
|
||||||
|
|
||||||
|
// 生命周期: 拦截器在请求处理之前调用,只有返回true才会继续调用下一个拦截器或者处理器,否则不会调用
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
|
log.info("鉴权拦截:{} {}", request.getMethod(), request.getRequestURI());
|
||||||
|
// 获取请求头上的Token
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
response.setCharacterEncoding("UTF-8");
|
||||||
|
response.setContentType("application/json; charset=utf-8");
|
||||||
|
Result result = null;
|
||||||
|
if (StringUtils.isEmpty(token)) {
|
||||||
|
log.info("请求头中无Authorization信息");
|
||||||
|
result = Result.error(ErrorCode.USER_NOT_LOGGED_IN);
|
||||||
|
response.getWriter().write(JSON.toJSONString(result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
UserAuth userAuth = LinxyunUtils.getUserAuth(token);
|
||||||
|
if (userAuth == null) {
|
||||||
|
// 如果为空,说明 token 无效
|
||||||
|
log.info("Token 无效:{}", token);
|
||||||
|
result = Result.error(ErrorCode.LOGIN_VALIDATION_ERROR);
|
||||||
|
response.getWriter().write(JSON.toJSONString(result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String userRole = userAuth.getUserRoles();
|
||||||
|
if (StringUtils.isEmpty(userRole)) {
|
||||||
|
log.info("用户权限为空:{}", userAuth.getUserRoles());
|
||||||
|
result = Result.error(ErrorCode.LOGIN_VALIDATION_ERROR);
|
||||||
|
response.getWriter().write(JSON.toJSONString(result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!linxyunProperties.getEntCode().equals(userAuth.getEntCode())) {
|
||||||
|
log.info("用户企业编码错误:{}", userAuth.getEntCode());
|
||||||
|
result = Result.error(ErrorCode.LOGIN_VALIDATION_ERROR);
|
||||||
|
response.getWriter().write(JSON.toJSONString(result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 验证用户是否拥有权限
|
||||||
|
Map<String, List<String>> roleMap = linxyunProperties.getRole();
|
||||||
|
if (!roleMap.containsKey(userAuth.getUserRoles())) {
|
||||||
|
log.info("用户权限未在系统权限中:{}", userAuth.getUserRoles());
|
||||||
|
result = Result.error(ErrorCode.LOGIN_VALIDATION_ERROR);
|
||||||
|
response.getWriter().write(JSON.toJSONString(result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<String> pathList = roleMap.get(userRole);
|
||||||
|
// 是否有权限访问该路径
|
||||||
|
if (!URLUtils.isUriAuthorized(request.getRequestURI(), pathList)) {
|
||||||
|
log.info("用户无权访问该路径:{}", request.getRequestURI());
|
||||||
|
result = Result.error(ErrorCode.USER_NO_AUTHORITY);
|
||||||
|
response.getWriter().write(JSON.toJSONString(result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
log.info("鉴权通过:{}", token);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生命周期: 拦截器在请求处理之后调用,但是此时还没有返回视图,只有返回true才会继续调用下一个拦截器或者处理器,否则不会调用
|
||||||
|
@Override
|
||||||
|
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生命周期: 拦截器在视图渲染之后调用,即在视图渲染完成之后,页面响应给客户端之前,只有返回true才会继续调用下一个拦截器或者处理器,否则不会调用
|
||||||
|
@Override
|
||||||
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -11,6 +11,7 @@ import com.linxyun.homework.mapper.TeacherQqMsgsMapper;
|
|||||||
import com.linxyun.homework.service.HomeworkAnswerService;
|
import com.linxyun.homework.service.HomeworkAnswerService;
|
||||||
import com.linxyun.homework.mapper.HomeworkAnswerMapper;
|
import com.linxyun.homework.mapper.HomeworkAnswerMapper;
|
||||||
import com.linxyun.homework.utils.StringUtils;
|
import com.linxyun.homework.utils.StringUtils;
|
||||||
|
import com.linxyun.homework.utils.TimeUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@ -42,9 +43,26 @@ public class HomeworkAnswerServiceImpl extends ServiceImpl<HomeworkAnswerMapper,
|
|||||||
log.error("msgId: " + msgId + " not found");
|
log.error("msgId: " + msgId + " not found");
|
||||||
return Result.error(ErrorCode.PARAMETER_ERROR);
|
return Result.error(ErrorCode.PARAMETER_ERROR);
|
||||||
}
|
}
|
||||||
if (!(teacherQqMsgs.getMsgContent().contains(answerMsg.getFile()) && teacherQqMsgs.getRemarks().contains(answerMsg.getContent()))) {
|
|
||||||
return Result.error(ErrorCode.PARAMETER_ERROR);
|
if (!StringUtils.isEmpty(answerMsg.getFile()) ) {
|
||||||
|
if (StringUtils.isEmpty(teacherQqMsgs.getMsgContent())) {
|
||||||
|
return Result.error(ErrorCode.PARAMETER_ERROR);
|
||||||
|
} else {
|
||||||
|
if (!teacherQqMsgs.getMsgContent().contains(answerMsg.getFile())) {
|
||||||
|
return Result.error(ErrorCode.PARAMETER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (!StringUtils.isEmpty(answerMsg.getContent())) {
|
||||||
|
if (StringUtils.isEmpty(teacherQqMsgs.getRemarks())) {
|
||||||
|
return Result.error(ErrorCode.PARAMETER_ERROR);
|
||||||
|
} else {
|
||||||
|
if (!teacherQqMsgs.getRemarks().contains(answerMsg.getContent())) {
|
||||||
|
return Result.error(ErrorCode.PARAMETER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HomeworkAnswer homeworkAnswer = new HomeworkAnswer();
|
HomeworkAnswer homeworkAnswer = new HomeworkAnswer();
|
||||||
homeworkAnswer.setMemberId(memberId);
|
homeworkAnswer.setMemberId(memberId);
|
||||||
if (StringUtils.isEmpty(title)) {
|
if (StringUtils.isEmpty(title)) {
|
||||||
@ -54,13 +72,13 @@ public class HomeworkAnswerServiceImpl extends ServiceImpl<HomeworkAnswerMapper,
|
|||||||
}
|
}
|
||||||
homeworkAnswer.setCreateType(1); // 班级可看
|
homeworkAnswer.setCreateType(1); // 班级可看
|
||||||
homeworkAnswer.setStudentId(teacherQqMsgs.getClassId());
|
homeworkAnswer.setStudentId(teacherQqMsgs.getClassId());
|
||||||
|
homeworkAnswer.setRemark(answerMsg.getContent().replace("|||", "。")); // 文字;
|
||||||
|
homeworkAnswer.setCreateTime(TimeUtils.getCurrentTime());
|
||||||
if(answerMsg.getFile() != null) {
|
if(answerMsg.getFile() != null) {
|
||||||
homeworkAnswer.setContentType(1);
|
homeworkAnswer.setContentType(1);
|
||||||
homeworkAnswer.setRemark(answerMsg.getContent());
|
|
||||||
homeworkAnswer.setContentFileId(answerMsg.getFile()); // 文件资源
|
homeworkAnswer.setContentFileId(answerMsg.getFile()); // 文件资源
|
||||||
} else {
|
} else {
|
||||||
homeworkAnswer.setContentType(0);
|
homeworkAnswer.setContentType(0);
|
||||||
homeworkAnswer.setContent(answerMsg.getContent().replace("|||", "。")); // 文字
|
|
||||||
}
|
}
|
||||||
int row = homeworkAnswerMapper.insert(homeworkAnswer);
|
int row = homeworkAnswerMapper.insert(homeworkAnswer);
|
||||||
if (row < 1) {
|
if (row < 1) {
|
||||||
|
@ -1,25 +1,23 @@
|
|||||||
package com.linxyun.homework.utils;
|
package com.linxyun.homework.utils;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
|
||||||
import com.linxyun.homework.common.enums.FileType;
|
import com.linxyun.homework.common.enums.FileType;
|
||||||
|
import com.linxyun.homework.common.properties.LinxyunProperties;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.coobird.thumbnailator.Thumbnails;
|
import net.coobird.thumbnailator.Thumbnails;
|
||||||
import okhttp3.*;
|
import okhttp3.Response;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import okhttp3.ResponseBody;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class FileUtils {
|
public class FileUtils {
|
||||||
private static final OkHttpClient client = new OkHttpClient();
|
|
||||||
|
|
||||||
@Value("${upload.base-url}")
|
private final LinxyunProperties linxyunProperties;
|
||||||
private String baseUrl;
|
|
||||||
|
|
||||||
@Value(value = "${upload.img-quality}")
|
|
||||||
private Float imgQuality = 1.0f;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载文件到指定目录
|
* 下载文件到指定目录
|
||||||
@ -29,17 +27,11 @@ public class FileUtils {
|
|||||||
* @throws IOException 如果发生 IO 异常
|
* @throws IOException 如果发生 IO 异常
|
||||||
*/
|
*/
|
||||||
public void downloadFile(String fileUrl, String targetDir, String fileName) throws IOException {
|
public void downloadFile(String fileUrl, String targetDir, String fileName) throws IOException {
|
||||||
// 构建请求
|
|
||||||
Request request = new Request.Builder()
|
|
||||||
.url(fileUrl)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// 执行请求
|
// 执行请求
|
||||||
try (Response response = client.newCall(request).execute()) {
|
try (Response response = HttpUtils.getResp(fileUrl)) {
|
||||||
if (!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
throw new IOException("文件下载失败, HTTP 响应码: " + response.code());
|
throw new IOException("文件下载失败, HTTP 响应码: " + response.code());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保目标目录存在
|
// 确保目标目录存在
|
||||||
File directory = new File(targetDir);
|
File directory = new File(targetDir);
|
||||||
if (!directory.exists() && !directory.mkdirs()) {
|
if (!directory.exists() && !directory.mkdirs()) {
|
||||||
@ -56,8 +48,7 @@ public class FileUtils {
|
|||||||
outputStream.write(buffer, 0, bytesRead);
|
outputStream.write(buffer, 0, bytesRead);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.info("文件下载完成: {}", targetDir + File.separator + fileName);
|
||||||
System.out.println("文件下载完成: " + targetDir + File.separator + fileName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,15 +62,10 @@ public class FileUtils {
|
|||||||
|
|
||||||
public String uploadFileByUrl(String fileUrl, String fileName) {
|
public String uploadFileByUrl(String fileUrl, String fileName) {
|
||||||
FileType fileType = FileType.fromExtension(fileName);
|
FileType fileType = FileType.fromExtension(fileName);
|
||||||
// 创建 GET 请求
|
|
||||||
Request request = new Request.Builder()
|
|
||||||
.url(fileUrl)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// 执行请求
|
// 执行请求
|
||||||
try (Response response = client.newCall(request).execute()) {
|
try (Response response = HttpUtils.getResp(fileUrl)) {
|
||||||
if (!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
log.error("Failed to download file: " + response.message());
|
log.error("Failed to download file: {}", response.message());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// 获取文件内容作为字节数组
|
// 获取文件内容作为字节数组
|
||||||
@ -88,23 +74,23 @@ public class FileUtils {
|
|||||||
// 如果是图片,进行压缩
|
// 如果是图片,进行压缩
|
||||||
if (fileType == FileType.IMAGE) {
|
if (fileType == FileType.IMAGE) {
|
||||||
try (ByteArrayOutputStream compressedOutputStream = new ByteArrayOutputStream()) {
|
try (ByteArrayOutputStream compressedOutputStream = new ByteArrayOutputStream()) {
|
||||||
log.info("压缩图片:" + fileUrl + " 图片质量:" + imgQuality);
|
log.info("压缩图片:{} 图片质量: {}", fileUrl, linxyunProperties.getUpload().getImgQuality());
|
||||||
// 压缩图片
|
// 压缩图片
|
||||||
Thumbnails.of(inputStream)
|
Thumbnails.of(inputStream)
|
||||||
.outputQuality(imgQuality) // 设置输出质量 (0~1)
|
.outputQuality(linxyunProperties.getUpload().getImgQuality()) // 设置输出质量 (0~1)
|
||||||
.scale(1.0) // 保持原尺寸(如需缩放可调整 scale 值或使用 size 方法)
|
.scale(1.0) // 保持原尺寸(如需缩放可调整 scale 值或使用 size 方法)
|
||||||
.toOutputStream(compressedOutputStream);
|
.toOutputStream(compressedOutputStream);
|
||||||
|
|
||||||
// 日志输出原始大小和压缩后大小
|
// 日志输出原始大小和压缩后大小
|
||||||
log.info("图片原始大小: " + responseBody.contentLength() + " 字节");
|
log.info("图片原始大小: {} 字节", responseBody.contentLength());
|
||||||
log.info("图片压缩后大小: " + compressedOutputStream.size() + " 字节");
|
log.info("图片压缩后大小: {} 字节", compressedOutputStream.size());
|
||||||
// 上传压缩后的图片
|
// 上传压缩后的图片
|
||||||
return uploadFile(compressedOutputStream.toByteArray(), fileName);
|
return LinxyunUtils.uploadFile(compressedOutputStream.toByteArray(), fileName);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 非图片直接上传
|
// 非图片直接上传
|
||||||
log.info("上传其它文件:" + fileUrl);
|
log.info("上传其它文件:{}", fileUrl);
|
||||||
return uploadFile(inputStream.readAllBytes(), fileName);
|
return LinxyunUtils.uploadFile(inputStream.readAllBytes(), fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -112,57 +98,4 @@ public class FileUtils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用 OkHttp 上传文件
|
|
||||||
*
|
|
||||||
* @param fileBytes 文件字节数组
|
|
||||||
* @param fileName 文件名
|
|
||||||
* @return 上传成功时返回服务器响应的 "data" 字段;否则返回 null
|
|
||||||
*/
|
|
||||||
public String uploadFile(byte[] fileBytes, String fileName) {
|
|
||||||
String uploadUrl = baseUrl + "/eslithe/uploadFile.action";
|
|
||||||
// 创建请求体
|
|
||||||
RequestBody fileBody = RequestBody.create(fileBytes, MediaType.parse("application/octet-stream"));
|
|
||||||
MultipartBody requestBody = new MultipartBody.Builder()
|
|
||||||
.setType(MultipartBody.FORM)
|
|
||||||
.addFormDataPart("file", fileName, fileBody)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// 创建请求
|
|
||||||
Request request = new Request.Builder()
|
|
||||||
.url(uploadUrl)
|
|
||||||
.post(requestBody)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// 执行请求
|
|
||||||
try (Response response = client.newCall(request).execute()) {
|
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
|
||||||
String responseBody = response.body().string();
|
|
||||||
log.info("FileUploadTool uploadFile result: " + responseBody);
|
|
||||||
|
|
||||||
// 解析响应
|
|
||||||
JSONObject jsonObject = JSONObject.parseObject(responseBody);
|
|
||||||
if (jsonObject != null
|
|
||||||
&& jsonObject.getBoolean("success") != null
|
|
||||||
&& jsonObject.getBoolean("success")
|
|
||||||
&& jsonObject.containsKey("data")) {
|
|
||||||
return jsonObject.getString("data");
|
|
||||||
} else {
|
|
||||||
log.error("FileUploadTool uploadFile failed: " + responseBody);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.error("FileUploadTool uploadFile failed, HTTP code: " + response.code());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} catch (IOException ex) {
|
|
||||||
log.error("FileUploadTool uploadFile exception: ", ex);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
109
src/main/java/com/linxyun/homework/utils/HttpUtils.java
Normal file
109
src/main/java/com/linxyun/homework/utils/HttpUtils.java
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package com.linxyun.homework.utils;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import okhttp3.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class HttpUtils {
|
||||||
|
|
||||||
|
private static final OkHttpClient client = new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(60, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(60, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(60, TimeUnit.SECONDS)
|
||||||
|
.retryOnConnectionFailure(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 通用请求方法,处理所有的 GET 和 POST 请求
|
||||||
|
private static JSONObject executeRequest(Request request) throws IOException {
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
log.error("Request failed: {} {}", response.code(), response.message());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (response.body() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return com.alibaba.fastjson2.JSONObject.parseObject(response.body().string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET 请求
|
||||||
|
public static JSONObject get(String url) throws IOException {
|
||||||
|
Request request = new Request.Builder().url(url).build();
|
||||||
|
return executeRequest(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Response getResp(String url) throws IOException {
|
||||||
|
Request request = new Request.Builder().url(url).build();
|
||||||
|
return client.newCall(request).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Response postResp(String url, RequestBody requestBody) throws IOException {
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.post(requestBody)
|
||||||
|
.build();
|
||||||
|
return client.newCall(request).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static JSONObject get(String url, Map<String, String> params) throws IOException {
|
||||||
|
String urlWithParams = buildUrlWithParams(url, params);
|
||||||
|
return get(urlWithParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JSONObject get(String url, Map<String, String> params, Headers headers) throws IOException {
|
||||||
|
String urlWithParams = buildUrlWithParams(url, params);
|
||||||
|
return get(urlWithParams, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JSONObject get(String url, Headers headers) throws IOException {
|
||||||
|
Request request = new Request.Builder().url(url).headers(headers).build();
|
||||||
|
return executeRequest(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST 请求
|
||||||
|
public static JSONObject post(String url, JSONObject body) throws IOException {
|
||||||
|
RequestBody requestBody = RequestBody.create(body.toJSONString(), MediaType.parse("application/json"));
|
||||||
|
Request request = new Request.Builder().url(url).post(requestBody).build();
|
||||||
|
return executeRequest(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JSONObject post(String url, JSONObject body, Map<String, String> params) throws IOException {
|
||||||
|
String urlWithParams = buildUrlWithParams(url, params);
|
||||||
|
RequestBody requestBody = RequestBody.create(body.toJSONString(), MediaType.parse("application/json"));
|
||||||
|
Request request = new Request.Builder().url(urlWithParams).post(requestBody).build();
|
||||||
|
return executeRequest(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JSONObject post(String url, JSONObject body, Headers headers) throws IOException {
|
||||||
|
RequestBody requestBody = RequestBody.create(body.toJSONString(), MediaType.parse("application/json"));
|
||||||
|
Request request = new Request.Builder().url(url).post(requestBody).headers(headers).build();
|
||||||
|
return executeRequest(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JSONObject post(String url, JSONObject body, Headers headers, Map<String, String> params) throws IOException {
|
||||||
|
String urlWithParams = buildUrlWithParams(url, params);
|
||||||
|
RequestBody requestBody = RequestBody.create(body.toJSONString(), MediaType.parse("application/json"));
|
||||||
|
Request request = new Request.Builder().url(urlWithParams).post(requestBody).headers(headers).build();
|
||||||
|
return executeRequest(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建带参数的 URL
|
||||||
|
private static String buildUrlWithParams(String url, Map<String, String> params) {
|
||||||
|
HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder();
|
||||||
|
if (params != null && !params.isEmpty()) {
|
||||||
|
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||||
|
urlBuilder.addQueryParameter(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return urlBuilder.build().toString();
|
||||||
|
}
|
||||||
|
}
|
162
src/main/java/com/linxyun/homework/utils/LinxyunUtils.java
Normal file
162
src/main/java/com/linxyun/homework/utils/LinxyunUtils.java
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
package com.linxyun.homework.utils;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.linxyun.homework.common.properties.LinxyunProperties;
|
||||||
|
import com.linxyun.homework.domain.dto.UserAuth;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.jodah.expiringmap.ExpirationPolicy;
|
||||||
|
import net.jodah.expiringmap.ExpiringMap;
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.MultipartBody;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LinxyunUtils {
|
||||||
|
|
||||||
|
private final static ExpiringMap<String, UserAuth> USER_AUTH_MAP = ExpiringMap.builder()
|
||||||
|
// 设置最大值,添加第11个entry时,会导致第1个立马过期(即使没到过期时间)。默认 Integer.MAX_VALUE
|
||||||
|
.maxSize(10)
|
||||||
|
// 允许 Map 元素具有各自的到期时间,并允许更改到期时间。
|
||||||
|
.variableExpiration()
|
||||||
|
// 设置过期时间,如果key不设置过期时间,key永久有效。
|
||||||
|
.expiration(1, TimeUnit.DAYS)
|
||||||
|
.asyncExpirationListener((key, value) -> {
|
||||||
|
log.info("USER_AUTH_MAP key数据被删除了 -> key={}, value={}", key, value);
|
||||||
|
})
|
||||||
|
//设置 Map 的过期策略
|
||||||
|
.expirationPolicy(ExpirationPolicy.CREATED)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private final LinxyunProperties linxyunProperties;
|
||||||
|
private static String url;
|
||||||
|
private static String projectName;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
log.info("LinxyunUtils init success");
|
||||||
|
url = linxyunProperties.getUrl();
|
||||||
|
projectName = linxyunProperties.getProject();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单点登录
|
||||||
|
* @param token
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static UserAuth userLoginAuth(String token) {
|
||||||
|
try {
|
||||||
|
if (StringUtils.isEmpty(token)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String url = getApiUrl("userLoginAuth");
|
||||||
|
JSONObject body = new JSONObject(Map.of("LoginID", token));
|
||||||
|
JSONObject result = HttpUtils.post(url, body);
|
||||||
|
if (result == null) {
|
||||||
|
log.error("LinxyunUtils-userLoginAuth result is null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
log.info("LinxyunUtils-userLoginAuth result: {}", result);
|
||||||
|
if (!result.getBoolean("success")) {
|
||||||
|
String msg = result.getString("msg");
|
||||||
|
log.error("LinxyunUtils-userLoginAuth result is not success: {}", msg);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String data = result.getString("data");
|
||||||
|
if (StringUtils.isEmpty(data)) {
|
||||||
|
log.error("LinxyunUtils-userLoginAuth result.data is null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
UserAuth userAuth = JSONObject.parseObject(data, UserAuth.class);
|
||||||
|
USER_AUTH_MAP.put(token, userAuth);
|
||||||
|
return userAuth;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("linxyunUtils.userLoginAuth error: {}", e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserAuth getUserAuth(String token) {
|
||||||
|
if (StringUtils.isEmpty(token)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
boolean isExist = USER_AUTH_MAP.containsKey(token);
|
||||||
|
if (isExist) {
|
||||||
|
// 存在,直接获取缓存的数据
|
||||||
|
return USER_AUTH_MAP.get(token);
|
||||||
|
}
|
||||||
|
return userLoginAuth(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getApiUrl(String path) {
|
||||||
|
String baseUrl = url + "/" + projectName;
|
||||||
|
if (StringUtils.isEmpty(path)) {
|
||||||
|
return baseUrl;
|
||||||
|
}
|
||||||
|
if (!path.startsWith("/")) {
|
||||||
|
path = "/" + path;
|
||||||
|
}
|
||||||
|
if (!path.endsWith(".action")) {
|
||||||
|
path += ".action";
|
||||||
|
}
|
||||||
|
return baseUrl + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 OkHttp 上传文件
|
||||||
|
*
|
||||||
|
* @param fileBytes 文件字节数组
|
||||||
|
* @param fileName 文件名
|
||||||
|
* @return 上传成功时返回服务器响应的 "data" 字段;否则返回 null
|
||||||
|
*/
|
||||||
|
public static String uploadFile(byte[] fileBytes, String fileName) {
|
||||||
|
String uploadUrl = url + "/eslithe/uploadFile.action";
|
||||||
|
// 创建请求体
|
||||||
|
RequestBody fileBody = RequestBody.create(fileBytes, MediaType.parse("application/octet-stream"));
|
||||||
|
MultipartBody requestBody = new MultipartBody.Builder()
|
||||||
|
.setType(MultipartBody.FORM)
|
||||||
|
.addFormDataPart("file", fileName, fileBody)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 执行请求
|
||||||
|
try (Response response = HttpUtils.postResp(uploadUrl, requestBody)) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
String responseBody = response.body().string();
|
||||||
|
log.info("FileUploadTool uploadFile result: {}", responseBody);
|
||||||
|
|
||||||
|
// 解析响应
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(responseBody);
|
||||||
|
if (jsonObject != null
|
||||||
|
&& jsonObject.getBoolean("success") != null
|
||||||
|
&& jsonObject.getBoolean("success")
|
||||||
|
&& jsonObject.containsKey("data")) {
|
||||||
|
return jsonObject.getString("data");
|
||||||
|
} else {
|
||||||
|
log.error("FileUploadTool uploadFile failed: {}", responseBody);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.error("FileUploadTool uploadFile failed, HTTP code: {}", response.code());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
log.error("FileUploadTool uploadFile exception: ", ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
UserAuth userAuth = LinxyunUtils.userLoginAuth("LoginID_20241205143442_000430");
|
||||||
|
System.out.println(userAuth);
|
||||||
|
}
|
||||||
|
}
|
35
src/main/java/com/linxyun/homework/utils/URLUtils.java
Normal file
35
src/main/java/com/linxyun/homework/utils/URLUtils.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package com.linxyun.homework.utils;
|
||||||
|
|
||||||
|
import org.springframework.util.AntPathMatcher;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class URLUtils {
|
||||||
|
|
||||||
|
private static final AntPathMatcher pathMatcher = new AntPathMatcher();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查请求的 URI 是否符合角色对应的路径列表
|
||||||
|
*
|
||||||
|
* @param requestUri 需要匹配的 URI
|
||||||
|
* @param pathList 角色对应的路径列表
|
||||||
|
* @return true 如果匹配;否则 false
|
||||||
|
*/
|
||||||
|
public static boolean isUriAuthorized(String requestUri, List<String> pathList) {
|
||||||
|
// 获取请求的 URI
|
||||||
|
if (requestUri == null || requestUri.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (pathList == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 遍历路径列表,检查是否有匹配项
|
||||||
|
for (String pathPattern : pathList) {
|
||||||
|
if (pathMatcher.match(pathPattern, requestUri)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果没有匹配到,返回 false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
30
src/main/resources/application-dev.yml
Normal file
30
src/main/resources/application-dev.yml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# 应用服务 WEB 访问端口
|
||||||
|
server:
|
||||||
|
port: 8080
|
||||||
|
servlet:
|
||||||
|
context-path: /customService
|
||||||
|
|
||||||
|
spring:
|
||||||
|
datasource: #定义数据源
|
||||||
|
#127.0.0.1为本机测试的ip,3306是mysql的端口号。serverTimezone是定义时区,照抄就好,mysql高版本需要定义这些东西
|
||||||
|
#useSSL也是某些高版本mysql需要问有没有用SSL连接
|
||||||
|
url: jdbc:mysql://117.89.254.176:8846/homeworkor?serverTimezone=GMT%2B8&useSSL=FALSE
|
||||||
|
username: root #数据库用户名,root为管理员
|
||||||
|
password: Home.lxy.com #该数据库用户的密码
|
||||||
|
# 使用druid数据源
|
||||||
|
type: com.alibaba.druid.pool.DruidDataSource
|
||||||
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
mail:
|
||||||
|
host: smtp.163.com
|
||||||
|
port: 465
|
||||||
|
protocol: smtps
|
||||||
|
username: wenxin_web@163.com
|
||||||
|
password: YCOUPMDBKDTQRAJR
|
||||||
|
default-encoding: UTF-8
|
||||||
|
to-address: 1731551615@qq.com
|
||||||
|
|
||||||
|
mirai:
|
||||||
|
bot:
|
||||||
|
qq: 418853946
|
||||||
|
# 监听类型 1为监听指定群的聊天消息, 2为监听指定群指定QQ的聊天消息
|
||||||
|
listening-type: 1
|
30
src/main/resources/application-prod.yml
Normal file
30
src/main/resources/application-prod.yml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# 应用服务 WEB 访问端口
|
||||||
|
server:
|
||||||
|
port: 8080
|
||||||
|
servlet:
|
||||||
|
context-path: /customService
|
||||||
|
|
||||||
|
spring:
|
||||||
|
datasource: #定义数据源
|
||||||
|
#127.0.0.1为本机测试的ip,3306是mysql的端口号。serverTimezone是定义时区,照抄就好,mysql高版本需要定义这些东西
|
||||||
|
#useSSL也是某些高版本mysql需要问有没有用SSL连接
|
||||||
|
url: jdbc:mysql://127.0.0.1:3306/homeworkor?serverTimezone=GMT%2B8&useSSL=FALSE
|
||||||
|
username: root #数据库用户名,root为管理员
|
||||||
|
password: Home.lxy.com #该数据库用户的密码
|
||||||
|
# 使用druid数据源
|
||||||
|
type: com.alibaba.druid.pool.DruidDataSource
|
||||||
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
mail:
|
||||||
|
host: smtp.163.com
|
||||||
|
port: 465
|
||||||
|
protocol: smtps
|
||||||
|
username: wenxin_web@163.com
|
||||||
|
password: YCOUPMDBKDTQRAJR
|
||||||
|
default-encoding: UTF-8
|
||||||
|
to-address: 1731551615@qq.com
|
||||||
|
|
||||||
|
mirai:
|
||||||
|
bot:
|
||||||
|
qq: 20243037
|
||||||
|
# 监听类型 1为监听指定群的聊天消息, 2为监听指定群指定QQ的聊天消息
|
||||||
|
listening-type: 1
|
@ -1,29 +1,28 @@
|
|||||||
# 应用服务 WEB 访问端口
|
spring:
|
||||||
server:
|
profiles:
|
||||||
port: 8080
|
active: dev
|
||||||
servlet:
|
|
||||||
context-path: /customService
|
|
||||||
|
|
||||||
spring: #springboot的配置
|
linxyun:
|
||||||
datasource: #定义数据源
|
url: http://www.linxyun.com
|
||||||
#127.0.0.1为本机测试的ip,3306是mysql的端口号。serverTimezone是定义时区,照抄就好,mysql高版本需要定义这些东西
|
# 企业编码
|
||||||
#useSSL也是某些高版本mysql需要问有没有用SSL连接
|
ent-code: 57
|
||||||
# url: jdbc:mysql://127.0.0.1:3306/homeworkor?serverTimezone=GMT%2B8&useSSL=FALSE
|
# 项目名称
|
||||||
url: jdbc:mysql://117.89.254.176:8846/homeworkor?serverTimezone=GMT%2B8&useSSL=FALSE
|
project: homeworkor
|
||||||
|
# 角色
|
||||||
username: root #数据库用户名,root为管理员
|
role:
|
||||||
password: Home.lxy.com #该数据库用户的密码
|
1101:
|
||||||
# 使用druid数据源
|
- /class/**
|
||||||
type: com.alibaba.druid.pool.DruidDataSource
|
1102:
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
- /user
|
||||||
mail:
|
# 白名单
|
||||||
host: smtp.163.com
|
white-list:
|
||||||
port: 465
|
- /swagger-ui.html
|
||||||
protocol: smtps
|
- /v3/api-docs/**
|
||||||
username: wenxin_web@163.com
|
- /doc.html
|
||||||
password: YCOUPMDBKDTQRAJR
|
- /error
|
||||||
default-encoding: UTF-8
|
upload:
|
||||||
to-address: 1731551615@qq.com
|
# 图片压缩质量 0~1
|
||||||
|
img-quality: 0.5
|
||||||
|
|
||||||
# mybatis-plus相关配置
|
# mybatis-plus相关配置
|
||||||
mybatis-plus:
|
mybatis-plus:
|
||||||
@ -46,7 +45,6 @@ mybatis-plus:
|
|||||||
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
|
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
|
||||||
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||||
|
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
file:
|
file:
|
||||||
# 输出的log文件名
|
# 输出的log文件名
|
||||||
@ -72,20 +70,9 @@ springdoc:
|
|||||||
- group: 'default'
|
- group: 'default'
|
||||||
paths-to-match: '/**'
|
paths-to-match: '/**'
|
||||||
packages-to-scan: com.linxyun.homework.controller
|
packages-to-scan: com.linxyun.homework.controller
|
||||||
|
|
||||||
# knife4j的增强配置,不需要增强可以不配
|
# knife4j的增强配置,不需要增强可以不配
|
||||||
knife4j:
|
knife4j:
|
||||||
enable: true
|
enable: true
|
||||||
setting:
|
setting:
|
||||||
language: zh_cn
|
language: zh_cn
|
||||||
|
|
||||||
mirai:
|
|
||||||
bot:
|
|
||||||
# qq: 20243037
|
|
||||||
# qq: 939948263
|
|
||||||
qq: 418853946
|
|
||||||
# 监听类型 1为监听指定群的聊天消息, 2为监听指定群指定QQ的聊天消息
|
|
||||||
listening-type: 1
|
|
||||||
upload:
|
|
||||||
base-url: http://www.linxyun.com
|
|
||||||
# 图片压缩质量 0~1
|
|
||||||
img-quality: 0.5
|
|
Loading…
Reference in New Issue
Block a user