feat: guava缓存/登录拦截器
This commit is contained in:
@@ -19,10 +19,19 @@
|
|||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
<version>3.8.1</version>
|
<version>3.0.7</version>
|
||||||
<scope>test</scope>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-loadbalancer</artifactId>
|
||||||
|
<version>3.0.6</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.28</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@@ -1,13 +0,0 @@
|
|||||||
package com.landaiqing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hello world!
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class App
|
|
||||||
{
|
|
||||||
public static void main( String[] args )
|
|
||||||
{
|
|
||||||
System.out.println( "Hello World!" );
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,22 @@
|
|||||||
|
package com.landaiqing.auth.api;
|
||||||
|
|
||||||
|
import com.landaiqing.auth.entity.AuthUserDTO;
|
||||||
|
import com.landaiqing.auth.entity.Result;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname UserFeignService
|
||||||
|
* @BelongsProject: qing-yu-club
|
||||||
|
* @BelongsPackage: com.landaiqing.auth.api
|
||||||
|
* @Author: landaiqing
|
||||||
|
* @CreateTime: 2024-03-03 19:57
|
||||||
|
* @Description: 用户服务feign
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@FeignClient("qing-yu-club-auth-dev")
|
||||||
|
public interface UserFeignService {
|
||||||
|
@RequestMapping("/user/getUserInfo")
|
||||||
|
Result<AuthUserDTO> getUserInfo(@RequestBody AuthUserDTO authUserDTO);
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
package com.landaiqing.auth.application.dto;
|
package com.landaiqing.auth.entity;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@@ -1,6 +1,5 @@
|
|||||||
package com.landaiqing.auth.common.entity;
|
package com.landaiqing.auth.entity;
|
||||||
|
|
||||||
import com.landaiqing.auth.common.enums.ResultCodeEnum;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
@@ -0,0 +1,29 @@
|
|||||||
|
package com.landaiqing.auth.entity;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public enum ResultCodeEnum {
|
||||||
|
|
||||||
|
SUCCESS(200,"成功"),
|
||||||
|
FAIL(500,"失败");
|
||||||
|
|
||||||
|
public int code;
|
||||||
|
|
||||||
|
public String desc;
|
||||||
|
|
||||||
|
ResultCodeEnum(int code,String desc){
|
||||||
|
this.code = code;
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ResultCodeEnum getByCode(int codeVal){
|
||||||
|
for(ResultCodeEnum resultCodeEnum : ResultCodeEnum.values()){
|
||||||
|
if(resultCodeEnum.code == codeVal){
|
||||||
|
return resultCodeEnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,38 +0,0 @@
|
|||||||
package com.landaiqing;
|
|
||||||
|
|
||||||
import junit.framework.Test;
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
import junit.framework.TestSuite;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unit test for simple App.
|
|
||||||
*/
|
|
||||||
public class AppTest
|
|
||||||
extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the test case
|
|
||||||
*
|
|
||||||
* @param testName name of the test case
|
|
||||||
*/
|
|
||||||
public AppTest( String testName )
|
|
||||||
{
|
|
||||||
super( testName );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the suite of tests being tested
|
|
||||||
*/
|
|
||||||
public static Test suite()
|
|
||||||
{
|
|
||||||
return new TestSuite( AppTest.class );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rigourous Test :-)
|
|
||||||
*/
|
|
||||||
public void testApp()
|
|
||||||
{
|
|
||||||
assertTrue( true );
|
|
||||||
}
|
|
||||||
}
|
|
@@ -32,6 +32,12 @@
|
|||||||
<artifactId>qing-yu-club-auth-domain</artifactId>
|
<artifactId>qing-yu-club-auth-domain</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.landaiqing</groupId>
|
||||||
|
<artifactId>qing-yu-club-auth-api</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@@ -3,9 +3,11 @@ package com.landaiqing.auth.application.config;
|
|||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
import com.landaiqing.auth.application.interceptor.LoginInterceptor;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -33,4 +35,9 @@ public class GlobalConfig extends WebMvcConfigurationSupport {
|
|||||||
MappingJackson2HttpMessageConverter converter=new MappingJackson2HttpMessageConverter(objectMapper);
|
MappingJackson2HttpMessageConverter converter=new MappingJackson2HttpMessageConverter(objectMapper);
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
protected void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(new LoginInterceptor())
|
||||||
|
.addPathPatterns("/**");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,42 @@
|
|||||||
|
package com.landaiqing.auth.application.context;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname LoginContextHolder
|
||||||
|
* @BelongsProject: qing-yu-club
|
||||||
|
* @BelongsPackage: com.landaiqing.subject.application.context
|
||||||
|
* @Author: landaiqing
|
||||||
|
* @CreateTime: 2024-03-03 18:11
|
||||||
|
* @Description: 登录上下文对象
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class LoginContextHolder {
|
||||||
|
private static final InheritableThreadLocal <Map<String,Object>> THREAD_LOCAL=new InheritableThreadLocal<>();
|
||||||
|
|
||||||
|
public static void set(String key,Object val){
|
||||||
|
Map<String,Object> map=getThreadLoacalMap();
|
||||||
|
map.put(key, val);
|
||||||
|
}
|
||||||
|
public static Object get(String key){
|
||||||
|
Map<String,Object> threadLoacalMap=getThreadLoacalMap();
|
||||||
|
return threadLoacalMap.get(key);
|
||||||
|
}
|
||||||
|
public static void remove(){
|
||||||
|
THREAD_LOCAL.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getLoginId(){
|
||||||
|
return (String) getThreadLoacalMap().get("loginId");
|
||||||
|
}
|
||||||
|
public static Map<String,Object> getThreadLoacalMap(){
|
||||||
|
Map<String,Object> map =THREAD_LOCAL.get();
|
||||||
|
if (Objects.isNull(map)){
|
||||||
|
map=new ConcurrentHashMap<>();
|
||||||
|
THREAD_LOCAL.set(map);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
@@ -6,7 +6,7 @@ import com.landaiqing.auth.application.convert.AuthPermissionDTOConverter;
|
|||||||
import com.landaiqing.auth.application.dto.AuthPermissionDTO;
|
import com.landaiqing.auth.application.dto.AuthPermissionDTO;
|
||||||
import com.landaiqing.auth.domain.entity.AuthPermissionBO;
|
import com.landaiqing.auth.domain.entity.AuthPermissionBO;
|
||||||
import com.landaiqing.auth.domain.service.AuthPermissionDomainService;
|
import com.landaiqing.auth.domain.service.AuthPermissionDomainService;
|
||||||
import com.landaiqing.auth.common.entity.Result;
|
import com.landaiqing.auth.entity.Result;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
@@ -4,9 +4,9 @@ import com.alibaba.fastjson.JSON;
|
|||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.landaiqing.auth.application.convert.AuthRoleDTOConverter;
|
import com.landaiqing.auth.application.convert.AuthRoleDTOConverter;
|
||||||
import com.landaiqing.auth.application.dto.AuthRoleDTO;
|
import com.landaiqing.auth.application.dto.AuthRoleDTO;
|
||||||
import com.landaiqing.auth.common.entity.Result;
|
|
||||||
import com.landaiqing.auth.domain.entity.AuthRoleBO;
|
import com.landaiqing.auth.domain.entity.AuthRoleBO;
|
||||||
import com.landaiqing.auth.domain.service.AuthRoleDomainService;
|
import com.landaiqing.auth.domain.service.AuthRoleDomainService;
|
||||||
|
import com.landaiqing.auth.entity.Result;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
@@ -4,9 +4,9 @@ import com.alibaba.fastjson.JSON;
|
|||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.landaiqing.auth.application.convert.AuthRolePermissionDTOConverter;
|
import com.landaiqing.auth.application.convert.AuthRolePermissionDTOConverter;
|
||||||
import com.landaiqing.auth.application.dto.AuthRolePermissionDTO;
|
import com.landaiqing.auth.application.dto.AuthRolePermissionDTO;
|
||||||
import com.landaiqing.auth.common.entity.Result;
|
|
||||||
import com.landaiqing.auth.domain.entity.AuthRolePermissionBO;
|
import com.landaiqing.auth.domain.entity.AuthRolePermissionBO;
|
||||||
import com.landaiqing.auth.domain.service.AuthRolePermissionDomainService;
|
import com.landaiqing.auth.domain.service.AuthRolePermissionDomainService;
|
||||||
|
import com.landaiqing.auth.entity.Result;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
@@ -5,10 +5,10 @@ import cn.dev33.satoken.stp.StpUtil;
|
|||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.landaiqing.auth.application.convert.AuthUserDTOConverter;
|
import com.landaiqing.auth.application.convert.AuthUserDTOConverter;
|
||||||
import com.landaiqing.auth.application.dto.AuthUserDTO;
|
|
||||||
import com.landaiqing.auth.common.entity.Result;
|
|
||||||
import com.landaiqing.auth.domain.entity.AuthUserBO;
|
import com.landaiqing.auth.domain.entity.AuthUserBO;
|
||||||
import com.landaiqing.auth.domain.service.AuthUserDomainService;
|
import com.landaiqing.auth.domain.service.AuthUserDomainService;
|
||||||
|
import com.landaiqing.auth.entity.AuthUserDTO;
|
||||||
|
import com.landaiqing.auth.entity.Result;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package com.landaiqing.auth.application.convert;
|
package com.landaiqing.auth.application.convert;
|
||||||
|
|
||||||
import com.landaiqing.auth.application.dto.AuthUserDTO;
|
|
||||||
import com.landaiqing.auth.domain.entity.AuthUserBO;
|
import com.landaiqing.auth.domain.entity.AuthUserBO;
|
||||||
|
import com.landaiqing.auth.entity.AuthUserDTO;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@@ -0,0 +1,31 @@
|
|||||||
|
package com.landaiqing.auth.application.interceptor;
|
||||||
|
|
||||||
|
import com.landaiqing.auth.application.context.LoginContextHolder;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname LoginInterceptor
|
||||||
|
* @BelongsProject: qing-yu-club
|
||||||
|
* @BelongsPackage: com.landaiqing.subject.application.interceptor
|
||||||
|
* @Author: landaiqing
|
||||||
|
* @CreateTime: 2024-03-03 18:05
|
||||||
|
* @Description: 登录拦截器
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class LoginInterceptor implements HandlerInterceptor {
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
|
String loginId = request.getHeader("loginId");
|
||||||
|
LoginContextHolder.set("loginId",loginId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
|
||||||
|
LoginContextHolder.remove();
|
||||||
|
}
|
||||||
|
}
|
@@ -24,7 +24,7 @@
|
|||||||
select id,
|
select id,
|
||||||
name,
|
name,
|
||||||
parent_id,
|
parent_id,
|
||||||
type,
|
`type`,
|
||||||
menu_url,
|
menu_url,
|
||||||
status, `show`, icon, permission_key, created_by, created_time, update_by, update_time, is_deleted
|
status, `show`, icon, permission_key, created_by, created_time, update_by, update_time, is_deleted
|
||||||
from auth_permission
|
from auth_permission
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
<!--查询指定行数据-->
|
<!--查询指定行数据-->
|
||||||
<select id="queryAllByLimit" resultMap="AuthPermissionMap">
|
<select id="queryAllByLimit" resultMap="AuthPermissionMap">
|
||||||
select
|
select
|
||||||
id, name, parent_id, type, menu_url, status, `show`, icon, permission_key, created_by, created_time, update_by,
|
id, name, parent_id, `type`, menu_url, status, `show`, icon, permission_key, created_by, created_time, update_by,
|
||||||
update_time, is_deleted
|
update_time, is_deleted
|
||||||
from auth_permission
|
from auth_permission
|
||||||
<where>
|
<where>
|
||||||
@@ -42,22 +42,22 @@
|
|||||||
and id = #{id}
|
and id = #{id}
|
||||||
</if>
|
</if>
|
||||||
<if test="name != null and name != ''">
|
<if test="name != null and name != ''">
|
||||||
and name = #{name}
|
and `name` = #{name}
|
||||||
</if>
|
</if>
|
||||||
<if test="parentId != null">
|
<if test="parentId != null">
|
||||||
and parent_id = #{parentId}
|
and parent_id = #{parentId}
|
||||||
</if>
|
</if>
|
||||||
<if test="type != null">
|
<if test="type != null">
|
||||||
and type = #{type}
|
and `type` = #{type}
|
||||||
</if>
|
</if>
|
||||||
<if test="menuUrl != null and menuUrl != ''">
|
<if test="menuUrl != null and menuUrl != ''">
|
||||||
and menu_url = #{menuUrl}
|
and menu_url = #{menuUrl}
|
||||||
</if>
|
</if>
|
||||||
<if test="status != null">
|
<if test="status != null">
|
||||||
and status = #{status}
|
and `status` = #{status}
|
||||||
</if>
|
</if>
|
||||||
<if test="show != null">
|
<if test="show != null">
|
||||||
and show = #{show}
|
and `show` = #{show}
|
||||||
</if>
|
</if>
|
||||||
<if test="icon != null and icon != ''">
|
<if test="icon != null and icon != ''">
|
||||||
and icon = #{icon}
|
and icon = #{icon}
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
and id = #{id}
|
and id = #{id}
|
||||||
</if>
|
</if>
|
||||||
<if test="name != null and name != ''">
|
<if test="name != null and name != ''">
|
||||||
and name = #{name}
|
and `name` = #{name}
|
||||||
</if>
|
</if>
|
||||||
<if test="parentId != null">
|
<if test="parentId != null">
|
||||||
and parent_id = #{parentId}
|
and parent_id = #{parentId}
|
||||||
@@ -104,10 +104,10 @@
|
|||||||
and menu_url = #{menuUrl}
|
and menu_url = #{menuUrl}
|
||||||
</if>
|
</if>
|
||||||
<if test="status != null">
|
<if test="status != null">
|
||||||
and status = #{status}
|
and `status` = #{status}
|
||||||
</if>
|
</if>
|
||||||
<if test="show != null">
|
<if test="show != null">
|
||||||
and show = #{show}
|
and `show` = #{show}
|
||||||
</if>
|
</if>
|
||||||
<if test="icon != null and icon != ''">
|
<if test="icon != null and icon != ''">
|
||||||
and icon = #{icon}
|
and icon = #{icon}
|
||||||
|
@@ -3,10 +3,12 @@ package com.landaiqing.subject.application.config;
|
|||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
import com.landaiqing.subject.application.interceptor.LoginInterceptor;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -34,4 +36,10 @@ public class GlobalConfig extends WebMvcConfigurationSupport {
|
|||||||
MappingJackson2HttpMessageConverter converter=new MappingJackson2HttpMessageConverter(objectMapper);
|
MappingJackson2HttpMessageConverter converter=new MappingJackson2HttpMessageConverter(objectMapper);
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(new LoginInterceptor())
|
||||||
|
.addPathPatterns("/**");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,44 @@
|
|||||||
|
package com.landaiqing.subject.application.context;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname LoginContextHolder
|
||||||
|
* @BelongsProject: qing-yu-club
|
||||||
|
* @BelongsPackage: com.landaiqing.subject.application.context
|
||||||
|
* @Author: landaiqing
|
||||||
|
* @CreateTime: 2024-03-03 18:11
|
||||||
|
* @Description: 登录上下文对象
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class LoginContextHolder {
|
||||||
|
private static final InheritableThreadLocal <Map<String,Object>> THREAD_LOCAL=new InheritableThreadLocal<>();
|
||||||
|
|
||||||
|
public static void set(String key,Object val){
|
||||||
|
Map<String,Object> map=getThreadLoacalMap();
|
||||||
|
map.put(key, val);
|
||||||
|
}
|
||||||
|
public static Object get(String key){
|
||||||
|
Map<String,Object> threadLoacalMap=getThreadLoacalMap();
|
||||||
|
return threadLoacalMap.get(key);
|
||||||
|
}
|
||||||
|
public static void remove(){
|
||||||
|
THREAD_LOCAL.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getLoginId(){
|
||||||
|
return (String) getThreadLoacalMap().get("loginId");
|
||||||
|
}
|
||||||
|
public static Map<String,Object> getThreadLoacalMap(){
|
||||||
|
Map<String,Object> map =THREAD_LOCAL.get();
|
||||||
|
if (Objects.isNull(map)){
|
||||||
|
map=new ConcurrentHashMap<>();
|
||||||
|
THREAD_LOCAL.set(map);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,32 @@
|
|||||||
|
package com.landaiqing.subject.application.controller;
|
||||||
|
|
||||||
|
import com.landaiqing.subject.infra.entity.UserInfo;
|
||||||
|
import com.landaiqing.subject.infra.rpc.UserRpc;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷题分类controller
|
||||||
|
*
|
||||||
|
* @author: landaiqing
|
||||||
|
* @date: 2024/3/3
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/subject/category")
|
||||||
|
@Slf4j
|
||||||
|
public class TestFeignController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserRpc userRpc;
|
||||||
|
|
||||||
|
@GetMapping("testFeign")
|
||||||
|
public void testFeign() {
|
||||||
|
UserInfo userInfo = userRpc.getUserInfo("jichi");
|
||||||
|
log.info("testFeign.userInfo:{}", userInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
package com.landaiqing.subject.application.interceptor;
|
||||||
|
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname FeignConfiguration
|
||||||
|
* @BelongsProject: qing-yu-club
|
||||||
|
* @BelongsPackage: com.landaiqing.subject.application.interceptor
|
||||||
|
* @Author: landaiqing
|
||||||
|
* @CreateTime: 2024-03-03 21:11
|
||||||
|
* @Description: TODO
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class FeignConfiguration {
|
||||||
|
@Bean
|
||||||
|
public RequestInterceptor requestInterceptor(){
|
||||||
|
return new FeignRequestInterceptor();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,37 @@
|
|||||||
|
package com.landaiqing.subject.application.interceptor;
|
||||||
|
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestAttributes;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname FeignRequestInterceptor
|
||||||
|
* @BelongsProject: qing-yu-club
|
||||||
|
* @BelongsPackage: com.landaiqing.subject.application.interceptor
|
||||||
|
* @Author: landaiqing
|
||||||
|
* @CreateTime: 2024-03-03 21:04
|
||||||
|
* @Description: Feign请求拦截器
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class FeignRequestInterceptor implements RequestInterceptor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(RequestTemplate requestTemplate) {
|
||||||
|
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
|
HttpServletRequest request = requestAttributes.getRequest();
|
||||||
|
if (Objects.nonNull(request)) {
|
||||||
|
String loginId = request.getHeader("loginId");
|
||||||
|
if (StringUtils.isNotBlank(loginId)) {
|
||||||
|
requestTemplate.header("loginId", loginId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
package com.landaiqing.subject.application.interceptor;
|
||||||
|
|
||||||
|
import com.landaiqing.subject.application.context.LoginContextHolder;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
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.Enumeration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname LoginInterceptor
|
||||||
|
* @BelongsProject: qing-yu-club
|
||||||
|
* @BelongsPackage: com.landaiqing.subject.application.interceptor
|
||||||
|
* @Author: landaiqing
|
||||||
|
* @CreateTime: 2024-03-03 18:05
|
||||||
|
* @Description: 登录拦截器
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class LoginInterceptor implements HandlerInterceptor {
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
|
String loginId = request.getHeader("loginId");
|
||||||
|
LoginContextHolder.set("loginId",loginId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
|
||||||
|
LoginContextHolder.remove();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,19 @@
|
|||||||
|
package com.landaiqing.subject.application.util;
|
||||||
|
|
||||||
|
import com.landaiqing.subject.application.context.LoginContextHolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname LoginUtil
|
||||||
|
* @BelongsProject: qing-yu-club
|
||||||
|
* @BelongsPackage: com.landaiqing.subject.application.util
|
||||||
|
* @Author: landaiqing
|
||||||
|
* @CreateTime: 2024-03-03 18:33
|
||||||
|
* @Description: 用户登录util
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class LoginUtil {
|
||||||
|
public static String getLoginId() {
|
||||||
|
return LoginContextHolder.getLoginId();
|
||||||
|
}
|
||||||
|
}
|
@@ -3,11 +3,11 @@ package com.landaiqing.subject.domain.service.impl;
|
|||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.landaiqing.subject.common.enums.CategoryTypeEnum;
|
import com.landaiqing.subject.common.enums.CategoryTypeEnum;
|
||||||
import com.landaiqing.subject.common.enums.IsDeletedFlagEnum;
|
import com.landaiqing.subject.common.enums.IsDeletedFlagEnum;
|
||||||
import com.landaiqing.subject.domain.config.ThreadPoolConfig;
|
|
||||||
import com.landaiqing.subject.domain.convert.SubjectCategoryConverter;
|
import com.landaiqing.subject.domain.convert.SubjectCategoryConverter;
|
||||||
import com.landaiqing.subject.domain.entity.SubjectCategoryBO;
|
import com.landaiqing.subject.domain.entity.SubjectCategoryBO;
|
||||||
import com.landaiqing.subject.domain.entity.SubjectLabelBO;
|
import com.landaiqing.subject.domain.entity.SubjectLabelBO;
|
||||||
import com.landaiqing.subject.domain.service.SubjectCategoryDomainService;
|
import com.landaiqing.subject.domain.service.SubjectCategoryDomainService;
|
||||||
|
import com.landaiqing.subject.domain.util.CacheUtil;
|
||||||
import com.landaiqing.subject.infra.basic.entity.SubjectCategory;
|
import com.landaiqing.subject.infra.basic.entity.SubjectCategory;
|
||||||
import com.landaiqing.subject.infra.basic.entity.SubjectLabel;
|
import com.landaiqing.subject.infra.basic.entity.SubjectLabel;
|
||||||
import com.landaiqing.subject.infra.basic.entity.SubjectMapping;
|
import com.landaiqing.subject.infra.basic.entity.SubjectMapping;
|
||||||
@@ -26,10 +26,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.FutureTask;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -45,6 +43,10 @@ public class SubjectCategoryDomainServiceImpl implements SubjectCategoryDomainSe
|
|||||||
@Resource
|
@Resource
|
||||||
private ThreadPoolExecutor labelThreadPool;
|
private ThreadPoolExecutor labelThreadPool;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CacheUtil cacheUtil;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: 新增分类
|
* @description: 新增分类
|
||||||
* @param: [subjectCategoryBO]
|
* @param: [subjectCategoryBO]
|
||||||
@@ -127,9 +129,17 @@ public class SubjectCategoryDomainServiceImpl implements SubjectCategoryDomainSe
|
|||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@Override
|
@Override
|
||||||
public List<SubjectCategoryBO> queryCategoryAndLabel(SubjectCategoryBO subjectCategoryBO) {
|
public List<SubjectCategoryBO> queryCategoryAndLabel(SubjectCategoryBO subjectCategoryBO) {
|
||||||
|
Long id = subjectCategoryBO.getId();
|
||||||
|
String cacheKey = "categoryAndLabel." + subjectCategoryBO.getId();
|
||||||
|
List<SubjectCategoryBO> subjectCategoryBOS = cacheUtil.getResult(cacheKey,
|
||||||
|
SubjectCategoryBO.class, (key) -> getSubjectCategoryBOS(id));
|
||||||
|
return subjectCategoryBOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<SubjectCategoryBO> getSubjectCategoryBOS(Long categoryId) {
|
||||||
// 查询当前分类下的所以的分类
|
// 查询当前分类下的所以的分类
|
||||||
SubjectCategory subjectCategory = new SubjectCategory();
|
SubjectCategory subjectCategory = new SubjectCategory();
|
||||||
subjectCategory.setParentId(subjectCategoryBO.getId());
|
subjectCategory.setParentId(categoryId);
|
||||||
subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
|
subjectCategory.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
|
||||||
List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);
|
List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);
|
||||||
if (log.isInfoEnabled()) {
|
if (log.isInfoEnabled()) {
|
||||||
@@ -142,30 +152,18 @@ public class SubjectCategoryDomainServiceImpl implements SubjectCategoryDomainSe
|
|||||||
CompletableFuture.supplyAsync(() -> getLabelBOList(category), labelThreadPool)
|
CompletableFuture.supplyAsync(() -> getLabelBOList(category), labelThreadPool)
|
||||||
).collect(Collectors.toList());
|
).collect(Collectors.toList());
|
||||||
completableFutureList.forEach(future -> {
|
completableFutureList.forEach(future -> {
|
||||||
|
|
||||||
|
Map<Long, List<SubjectLabelBO>> resultMap = null;
|
||||||
try {
|
try {
|
||||||
Map<Long, List<SubjectLabelBO>> resultMap = future.get();
|
resultMap = future.get();
|
||||||
map.putAll(resultMap);
|
} catch (InterruptedException e) {
|
||||||
} catch (Exception e) {
|
throw new RuntimeException(e);
|
||||||
e.printStackTrace();
|
} catch (ExecutionException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
map.putAll(resultMap);
|
||||||
|
|
||||||
});
|
});
|
||||||
// // 一次获取标签信息
|
|
||||||
// List<FutureTask<Map<Long, List<SubjectLabelBO>>>> futureTaskList = new LinkedList<>();
|
|
||||||
// Map<Long, List<SubjectLabelBO>> map = new HashMap<>();
|
|
||||||
// //线程池并发调用
|
|
||||||
// categoryBOList.forEach(category -> {
|
|
||||||
// FutureTask<Map<Long, List<SubjectLabelBO>>> futureTask = new FutureTask<>(() ->
|
|
||||||
// getLabelBOList(category));
|
|
||||||
// futureTaskList.add(futureTask);
|
|
||||||
// labelThreadPool.submit(futureTask);
|
|
||||||
// });
|
|
||||||
// for (FutureTask<Map<Long, List<SubjectLabelBO>>> futureTask : futureTaskList) {
|
|
||||||
// Map<Long, List<SubjectLabelBO>> resultMap = futureTask.get();
|
|
||||||
// if (CollectionUtils.isEmpty(resultMap)) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// map.putAll(resultMap);
|
|
||||||
// }
|
|
||||||
categoryBOList.forEach(categoryBO -> {
|
categoryBOList.forEach(categoryBO -> {
|
||||||
categoryBO.setLabelBOList(map.get(categoryBO.getId()));
|
categoryBO.setLabelBOList(map.get(categoryBO.getId()));
|
||||||
});
|
});
|
||||||
|
@@ -0,0 +1,53 @@
|
|||||||
|
package com.landaiqing.subject.domain.util;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.google.common.cache.Cache;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname CacheUtil
|
||||||
|
* @BelongsProject: qing-yu-club
|
||||||
|
* @BelongsPackage: com.landaiqing.subject.domain.util
|
||||||
|
* @Author: landaiqing
|
||||||
|
* @CreateTime: 2024-03-03 21:31
|
||||||
|
* @Description: 缓存工具类
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class CacheUtil<K, V> {
|
||||||
|
private Cache<String, String> localCache =
|
||||||
|
CacheBuilder.newBuilder()
|
||||||
|
.maximumSize(5000)
|
||||||
|
.expireAfterWrite(10, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public List<V> getResult(String cacheKey, Class<V> clazz,
|
||||||
|
Function<String, List<V>> function) {
|
||||||
|
List<V> resultList = new ArrayList<>();
|
||||||
|
String content = localCache.getIfPresent(cacheKey);
|
||||||
|
if (StringUtils.isNotBlank(content)) {
|
||||||
|
resultList = JSON.parseArray(content, clazz);
|
||||||
|
} else {
|
||||||
|
resultList = function.apply(cacheKey);
|
||||||
|
if (!CollectionUtils.isEmpty(resultList)) {
|
||||||
|
localCache.put(cacheKey, JSON.toJSONString(resultList));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<K, V> getMapResult(String cacheKey, Class<V> clazz,
|
||||||
|
Function<String, Map<K, V>> function) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
}
|
@@ -51,5 +51,10 @@
|
|||||||
<artifactId>qing-yu-club-common</artifactId>
|
<artifactId>qing-yu-club-common</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.landaiqing</groupId>
|
||||||
|
<artifactId>qing-yu-club-auth-api</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@@ -0,0 +1,19 @@
|
|||||||
|
package com.landaiqing.subject.infra.entity;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname UserInfo
|
||||||
|
* @BelongsProject: qing-yu-club
|
||||||
|
* @BelongsPackage: com.landaiqing.subject.infra.entity
|
||||||
|
* @Author: landaiqing
|
||||||
|
* @CreateTime: 2024-03-03 20:13
|
||||||
|
* @Description: TODO
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UserInfo {
|
||||||
|
private String userName;
|
||||||
|
|
||||||
|
private String nickName;
|
||||||
|
}
|
@@ -0,0 +1,39 @@
|
|||||||
|
package com.landaiqing.subject.infra.rpc;
|
||||||
|
|
||||||
|
import com.landaiqing.auth.api.UserFeignService;
|
||||||
|
import com.landaiqing.auth.entity.AuthUserDTO;
|
||||||
|
import com.landaiqing.auth.entity.Result;
|
||||||
|
import com.landaiqing.subject.infra.entity.UserInfo;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname UserRpc
|
||||||
|
* @BelongsProject: qing-yu-club
|
||||||
|
* @BelongsPackage: com.landaiqing.subject.infra.rpc
|
||||||
|
* @Author: landaiqing
|
||||||
|
* @CreateTime: 2024-03-03 20:11
|
||||||
|
* @Description: TODO
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class UserRpc {
|
||||||
|
@Resource
|
||||||
|
private UserFeignService userFeignService;
|
||||||
|
|
||||||
|
public UserInfo getUserInfo(String userName) {
|
||||||
|
AuthUserDTO authUserDTO = new AuthUserDTO();
|
||||||
|
authUserDTO.setUserName(userName);
|
||||||
|
Result<AuthUserDTO> result = userFeignService.getUserInfo(authUserDTO);
|
||||||
|
UserInfo userInfo = new UserInfo();
|
||||||
|
if (!result.getSuccess()) {
|
||||||
|
return userInfo;
|
||||||
|
|
||||||
|
}
|
||||||
|
AuthUserDTO data = result.getData();
|
||||||
|
userInfo.setUserName(data.getUserName());
|
||||||
|
userInfo.setNickName(data.getNickName());
|
||||||
|
return userInfo;
|
||||||
|
}
|
||||||
|
}
|
@@ -3,6 +3,7 @@ package com.landaiqing.subject;
|
|||||||
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.cloud.openfeign.EnableFeignClients;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,6 +15,7 @@ import org.springframework.context.annotation.ComponentScan;
|
|||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@ComponentScan("com.landaiqing")
|
@ComponentScan("com.landaiqing")
|
||||||
@MapperScan("com.landaiqing.**.mapper")
|
@MapperScan("com.landaiqing.**.mapper")
|
||||||
|
@EnableFeignClients(basePackages = "com.landaiqing")
|
||||||
public class SubjectApplication {
|
public class SubjectApplication {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(SubjectApplication.class);
|
SpringApplication.run(SubjectApplication.class);
|
||||||
|
Reference in New Issue
Block a user